feat: P0 — MCP Tool类型(36) + Server框架 + 7个核心Tool实现
S-001: packages/shared/src/mcp/tools.ts — 36 Tool接口定义(10模块) S-002: packages/shared/src/mcp/config.ts — DeviceConfig/Gateway类型 C-001: packages/server/src/index.ts — MCP Server框架+SSE传输 C-002~011: packages/server/src/tools.ts — 7个P0核心Tool - file_list, file_read, file_write, file_move - exec, process_list, sysinfo packages/server/src/main.ts — 入口, 环境变量配置
This commit is contained in:
84
packages/server/src/index.ts
Normal file
84
packages/server/src/index.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* C-001: MCP Server Framework
|
||||
*
|
||||
* Bootstrap the MCP server with SSE transport using @modelcontextprotocol/sdk.
|
||||
* Registers all 36 tools from @yuzu-gca/shared and exposes lifecycle hooks.
|
||||
*/
|
||||
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
||||
import { ALL_TOOL_DEFS, type ToolDef, type DeviceConfig } from "@yuzu-gca/shared";
|
||||
|
||||
export interface ServerOptions {
|
||||
config: DeviceConfig;
|
||||
toolHandlers: Map<string, (args: any) => Promise<any>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an MCP Server instance with all tools registered.
|
||||
* Call `server.connect(transport)` to start handling requests.
|
||||
*/
|
||||
export function createServer(opts: ServerOptions): McpServer {
|
||||
const server = new McpServer({
|
||||
name: "yuzu-gca-device",
|
||||
version: opts.config.identity.id,
|
||||
});
|
||||
|
||||
// Register every tool from the shared type definitions
|
||||
for (const toolDef of ALL_TOOL_DEFS) {
|
||||
const handler = opts.toolHandlers.get(toolDef.name);
|
||||
if (handler) {
|
||||
server.tool(
|
||||
toolDef.name,
|
||||
toolDef.description,
|
||||
toolDef.inputSchema.properties,
|
||||
async (args: any) => {
|
||||
const result = await handler(args);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Register placeholder for unimplemented tools
|
||||
server.tool(
|
||||
toolDef.name,
|
||||
toolDef.description,
|
||||
toolDef.inputSchema.properties,
|
||||
async () => ({
|
||||
content: [{ type: "text", text: JSON.stringify({ error: "Tool not yet implemented", tool: toolDef.name }) }],
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server with SSE transport on a given port.
|
||||
*/
|
||||
export async function startServer(
|
||||
server: McpServer,
|
||||
port: number = 3001,
|
||||
): Promise<void> {
|
||||
const transport = new SSEServerTransport({
|
||||
port,
|
||||
endpoint: "/sse",
|
||||
});
|
||||
|
||||
await server.connect(transport);
|
||||
console.log(`[Yuzu-GCA] MCP Server listening on :${port}/sse`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience — create + start in one call.
|
||||
*/
|
||||
export async function bootstrap(
|
||||
opts: ServerOptions,
|
||||
port?: number,
|
||||
): Promise<McpServer> {
|
||||
const server = createServer(opts);
|
||||
await startServer(server, port);
|
||||
return server;
|
||||
}
|
||||
66
packages/server/src/main.ts
Normal file
66
packages/server/src/main.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Yuzu-GCA MCP Server Entry Point
|
||||
*
|
||||
* Usage: node dist/main.js
|
||||
* Or: npx tsx src/main.ts
|
||||
*/
|
||||
|
||||
import { bootstrap, type ServerOptions } from "./index.js";
|
||||
import * as tools from "./tools.js";
|
||||
import type { DeviceConfig, GatewayConfig } from "@yuzu-gca/shared";
|
||||
import * as os from "node:os";
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
||||
// Build device config from environment
|
||||
const config: DeviceConfig = {
|
||||
identity: {
|
||||
id: process.env.GCA_DEVICE_ID ?? randomUUID(),
|
||||
name: process.env.GCA_DEVICE_NAME ?? os.hostname(),
|
||||
platform: os.platform(),
|
||||
arch: os.arch(),
|
||||
hostname: os.hostname(),
|
||||
osVersion: os.release(),
|
||||
},
|
||||
gateway: {
|
||||
url: process.env.GCA_GATEWAY_URL ?? "http://localhost:3000",
|
||||
transport: (process.env.GCA_TRANSPORT as any) ?? "sse",
|
||||
reconnectDelay: 1000,
|
||||
maxReconnectDelay: 30000,
|
||||
heartbeatInterval: 15000,
|
||||
},
|
||||
capabilities: [
|
||||
"device_info", "device_status",
|
||||
"exec", "process_list",
|
||||
"file_list", "file_read", "file_write", "file_move",
|
||||
"sysinfo",
|
||||
],
|
||||
logLevel: (process.env.GCA_LOG_LEVEL as any) ?? "info",
|
||||
};
|
||||
|
||||
// Build tool handlers map
|
||||
const toolHandlers = new Map<string, (args: any) => Promise<any>>([
|
||||
["file_list", tools.file_list],
|
||||
["file_read", tools.file_read],
|
||||
["file_write", tools.file_write],
|
||||
["file_move", tools.file_move],
|
||||
["exec", tools.exec],
|
||||
["process_list",tools.process_list],
|
||||
["sysinfo", tools.sysinfo],
|
||||
]);
|
||||
|
||||
const opts: ServerOptions = { config, toolHandlers };
|
||||
const port = Number(process.env.GCA_PORT ?? 3001);
|
||||
|
||||
console.log(`[Yuzu-GCA] Starting MCP Server...`);
|
||||
console.log(` Device: ${config.identity.name} (${config.identity.platform}/${config.identity.arch})`);
|
||||
console.log(` Gateway: ${config.gateway.url}`);
|
||||
console.log(` Tools: ${toolHandlers.size} implemented`);
|
||||
console.log(` Port: ${port}`);
|
||||
|
||||
bootstrap(opts, port).then(() => {
|
||||
console.log(`[Yuzu-GCA] Ready.`);
|
||||
}).catch(err => {
|
||||
console.error(`[Yuzu-GCA] Fatal:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
148
packages/server/src/tools.ts
Normal file
148
packages/server/src/tools.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* P0 Core Tool Implementations
|
||||
*
|
||||
* file_list, file_read, file_write, file_move, exec, process_list, sysinfo.
|
||||
* These map to C-002 through C-011 in the backlog.
|
||||
*/
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { execSync, spawn } from "node:child_process";
|
||||
import * as os from "node:os";
|
||||
|
||||
// ── C-002: file_list ────────────────────────────────────────
|
||||
export async function file_list(args: {
|
||||
path: string;
|
||||
recursive?: boolean;
|
||||
}): Promise<any> {
|
||||
const dir = args.path || ".";
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
const result = entries.map(e => ({
|
||||
name: e.name,
|
||||
type: e.isDirectory() ? "dir" : e.isFile() ? "file" : "other",
|
||||
size: e.isFile() ? fs.statSync(path.join(dir, e.name)).size : undefined,
|
||||
}));
|
||||
return { path: dir, entries: result, count: result.length };
|
||||
}
|
||||
|
||||
// ── C-003: file_read ────────────────────────────────────────
|
||||
export async function file_read(args: {
|
||||
path: string;
|
||||
encoding?: string;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
}): Promise<any> {
|
||||
const encoding = (args.encoding === "base64" ? "base64" : "utf8") as BufferEncoding;
|
||||
let content = fs.readFileSync(args.path, encoding);
|
||||
if (encoding === "utf8") {
|
||||
const lines = (content as string).split("\n");
|
||||
const start = args.offset ?? 0;
|
||||
const end = args.limit ? start + args.limit : lines.length;
|
||||
content = lines.slice(start, end).join("\n");
|
||||
}
|
||||
return { path: args.path, content, size: fs.statSync(args.path).size };
|
||||
}
|
||||
|
||||
// ── C-004: file_write ───────────────────────────────────────
|
||||
export async function file_write(args: {
|
||||
path: string;
|
||||
content: string;
|
||||
encoding?: string;
|
||||
}): Promise<any> {
|
||||
const encoding = args.encoding === "base64" ? "base64" : "utf8";
|
||||
fs.mkdirSync(path.dirname(args.path), { recursive: true });
|
||||
fs.writeFileSync(args.path, args.content, encoding as BufferEncoding);
|
||||
return { ok: true, path: args.path, size: fs.statSync(args.path).size };
|
||||
}
|
||||
|
||||
// ── C-005: file_move ────────────────────────────────────────
|
||||
export async function file_move(args: {
|
||||
from: string;
|
||||
to: string;
|
||||
}): Promise<any> {
|
||||
fs.mkdirSync(path.dirname(args.to), { recursive: true });
|
||||
fs.renameSync(args.from, args.to);
|
||||
return { ok: true, from: args.from, to: args.to };
|
||||
}
|
||||
|
||||
// ── C-008: exec ─────────────────────────────────────────────
|
||||
export async function exec(args: {
|
||||
command: string;
|
||||
cwd?: string;
|
||||
timeout?: number;
|
||||
}): Promise<any> {
|
||||
const timeout = args.timeout ?? 30000;
|
||||
try {
|
||||
const stdout = execSync(args.command, {
|
||||
cwd: args.cwd ?? process.cwd(),
|
||||
timeout,
|
||||
encoding: "utf8",
|
||||
maxBuffer: 10 * 1024 * 1024, // 10MB
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
return { ok: true, stdout: stdout.toString(), stderr: "" };
|
||||
} catch (err: any) {
|
||||
return {
|
||||
ok: false,
|
||||
stdout: err.stdout?.toString() ?? "",
|
||||
stderr: err.stderr?.toString() ?? "",
|
||||
exitCode: err.status ?? -1,
|
||||
signal: err.signal,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ── C-010: process_list ─────────────────────────────────────
|
||||
export async function process_list(args: {
|
||||
filter?: string;
|
||||
}): Promise<any> {
|
||||
let stdout: string;
|
||||
try {
|
||||
if (process.platform === "win32") {
|
||||
stdout = execSync("tasklist /FO CSV /NH", { encoding: "utf8" }).toString();
|
||||
} else {
|
||||
stdout = execSync("ps aux --no-headers", { encoding: "utf8" }).toString();
|
||||
}
|
||||
} catch {
|
||||
return { error: "Failed to list processes" };
|
||||
}
|
||||
|
||||
const processes = stdout.trim().split("\n").map(line => {
|
||||
if (process.platform === "win32") {
|
||||
const [name, pid, , mem] = line.replace(/"/g, "").split(",");
|
||||
return { name: name?.trim(), pid: Number(pid), mem: mem?.trim() };
|
||||
}
|
||||
const parts = line.trim().split(/\s+/);
|
||||
return { user: parts[0], pid: Number(parts[1]), cpu: parts[2], mem: parts[3], name: parts[10] };
|
||||
});
|
||||
|
||||
const filtered = args.filter
|
||||
? processes.filter(p => p.name?.toLowerCase().includes(args.filter!.toLowerCase()))
|
||||
: processes.slice(0, 50);
|
||||
|
||||
return { count: filtered.length, processes: filtered };
|
||||
}
|
||||
|
||||
// ── C-011: sysinfo ──────────────────────────────────────────
|
||||
export async function sysinfo(_args: {}): Promise<any> {
|
||||
const cpuUsage = os.loadavg();
|
||||
const totalMem = os.totalmem();
|
||||
const freeMem = os.freemem();
|
||||
const uptime = os.uptime();
|
||||
|
||||
return {
|
||||
hostname: os.hostname(),
|
||||
platform: os.platform(),
|
||||
arch: os.arch(),
|
||||
cpus: os.cpus().length,
|
||||
loadavg: cpuUsage,
|
||||
memory: {
|
||||
total: totalMem,
|
||||
free: freeMem,
|
||||
used: totalMem - freeMem,
|
||||
percent: Math.round(((totalMem - freeMem) / totalMem) * 100),
|
||||
},
|
||||
uptime,
|
||||
node: process.version,
|
||||
};
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
export { parseVersion, compareVersion, checkUpdate, semverGt } from './updater/index';
|
||||
export type { GcaVersion, Manifest, ManifestBuild } from './updater/index';
|
||||
export { parseVersion, compareVersion, checkUpdate, semverGt } from './updater/index.js';
|
||||
export type { GcaVersion, Manifest, ManifestBuild } from './updater/index.js';
|
||||
export * from './mcp/index.js';
|
||||
|
||||
47
packages/shared/src/mcp/config.ts
Normal file
47
packages/shared/src/mcp/config.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* S-002: Device Configuration Types
|
||||
*/
|
||||
|
||||
/** Connection mode for the Gateway */
|
||||
export type TransportMode = "sse" | "websocket" | "stdio";
|
||||
|
||||
export interface GatewayConfig {
|
||||
url: string;
|
||||
token?: string;
|
||||
transport: TransportMode;
|
||||
reconnectDelay: number; // ms, default 1000
|
||||
maxReconnectDelay: number; // ms, default 30000
|
||||
heartbeatInterval: number; // ms, default 15000
|
||||
}
|
||||
|
||||
export interface DeviceIdentity {
|
||||
id: string; // unique device ID (UUID)
|
||||
name: string; // human-readable name
|
||||
platform: NodeJS.Platform;
|
||||
arch: string;
|
||||
hostname: string;
|
||||
osVersion: string;
|
||||
}
|
||||
|
||||
export interface ProxyConfig {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
auth?: { username: string; password: string };
|
||||
}
|
||||
|
||||
export interface DeviceConfig {
|
||||
identity: DeviceIdentity;
|
||||
gateway: GatewayConfig;
|
||||
proxy?: ProxyConfig;
|
||||
capabilities: string[]; // enabled MCP tool names
|
||||
logLevel: "debug" | "info" | "warn" | "error";
|
||||
}
|
||||
|
||||
export const DEFAULT_GATEWAY_CONFIG: GatewayConfig = {
|
||||
url: "http://localhost:3000",
|
||||
transport: "sse",
|
||||
reconnectDelay: 1000,
|
||||
maxReconnectDelay: 30000,
|
||||
heartbeatInterval: 15000,
|
||||
};
|
||||
2
packages/shared/src/mcp/index.ts
Normal file
2
packages/shared/src/mcp/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./tools.js";
|
||||
export * from "./config.js";
|
||||
375
packages/shared/src/mcp/tools.ts
Normal file
375
packages/shared/src/mcp/tools.ts
Normal file
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* S-001: MCP Tool Types — 36 Tool definitions for Yuzu-GCA
|
||||
*
|
||||
* Each Tool follows the @modelcontextprotocol/sdk shape:
|
||||
* { name, description, inputSchema }
|
||||
*
|
||||
* Organized by module per docs/backlog:
|
||||
* Module 1: Device Management (5 tools)
|
||||
* Module 2: Command Execution (4 tools)
|
||||
* Module 3: File Operations (6 tools)
|
||||
* Module 4: System Control (4 tools)
|
||||
* Module 5: Remote Desktop (4 tools)
|
||||
* Module 6: AI Manipulation (4 tools)
|
||||
* Module 7: Network (3 tools)
|
||||
* Module 8: Hardware (3 tools)
|
||||
* Module 9: Developer Tools (2 tools)
|
||||
* Module 10: Media (1 tool)
|
||||
*/
|
||||
|
||||
import type { z } from "zod";
|
||||
|
||||
// ── JSON Schema primitive aliases ──────────────────────────
|
||||
const str = (desc: string) => ({ type: "string" as const, description: desc });
|
||||
const num = (desc: string) => ({ type: "number" as const, description: desc });
|
||||
const bool = (desc: string) => ({ type: "boolean" as const, description: desc });
|
||||
const arr = (items: any, desc: string) => ({ type: "array" as const, items, description: desc });
|
||||
const obj = (props: Record<string,any>, required: string[], desc: string) => ({
|
||||
type: "object" as const, properties: props, required, description: desc,
|
||||
});
|
||||
|
||||
// ── Tool definition type ───────────────────────────────────
|
||||
export interface ToolDef {
|
||||
name: string;
|
||||
description: string;
|
||||
inputSchema: {
|
||||
type: "object";
|
||||
properties: Record<string, any>;
|
||||
required?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface ToolCategory {
|
||||
module: number;
|
||||
name: string;
|
||||
tools: ToolDef[];
|
||||
}
|
||||
|
||||
// ── Module 1: Device Management (5 tools) ──────────────────
|
||||
export const DEVICE_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "device_info",
|
||||
description: "Get device hardware/OS information (CPU, RAM, hostname, platform, arch)",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
{
|
||||
name: "device_list",
|
||||
description: "List all connected devices known to the Gateway",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
{
|
||||
name: "device_status",
|
||||
description: "Get current connection status and health of a specific device",
|
||||
inputSchema: obj({ deviceId: str("Target device ID (default: self)") }, [], ""),
|
||||
},
|
||||
{
|
||||
name: "device_register",
|
||||
description: "Register this device with the Gateway with capabilities and metadata",
|
||||
inputSchema: obj({
|
||||
name: str("Human-readable device name"),
|
||||
capabilities: arr(str("capability"), "List of capability strings"),
|
||||
}, ["name"], ""),
|
||||
},
|
||||
{
|
||||
name: "device_unregister",
|
||||
description: "Unregister from Gateway (graceful disconnect)",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 2: Command Execution (4 tools) ──────────────────
|
||||
export const EXEC_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "exec",
|
||||
description: "Execute a shell command and return stdout/stderr. 30s timeout.",
|
||||
inputSchema: obj({
|
||||
command: str("Shell command to execute"),
|
||||
cwd: str("Working directory (optional)"),
|
||||
timeout: num("Timeout in ms (default 30000)"),
|
||||
}, ["command"], ""),
|
||||
},
|
||||
{
|
||||
name: "exec_background",
|
||||
description: "Start a long-running command and return a process ID for later control",
|
||||
inputSchema: obj({
|
||||
command: str("Shell command to execute"),
|
||||
cwd: str("Working directory (optional)"),
|
||||
}, ["command"], ""),
|
||||
},
|
||||
{
|
||||
name: "process_list",
|
||||
description: "List running processes with PID, name, CPU%, memory",
|
||||
inputSchema: obj({
|
||||
filter: str("Optional name filter (substring match)"),
|
||||
}, [], ""),
|
||||
},
|
||||
{
|
||||
name: "process_kill",
|
||||
description: "Kill a process by PID",
|
||||
inputSchema: obj({
|
||||
pid: num("Process ID to kill"),
|
||||
signal: str("Signal (default: SIGTERM)"),
|
||||
}, ["pid"], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 3: File Operations (6 tools) ────────────────────
|
||||
export const FILE_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "file_list",
|
||||
description: "List files and directories at a given path",
|
||||
inputSchema: obj({
|
||||
path: str("Directory path to list"),
|
||||
recursive: bool("Recursive listing (default false)"),
|
||||
}, ["path"], ""),
|
||||
},
|
||||
{
|
||||
name: "file_read",
|
||||
description: "Read contents of a file (text or binary as base64)",
|
||||
inputSchema: obj({
|
||||
path: str("File path to read"),
|
||||
encoding: str("utf8 | base64 (default utf8)"),
|
||||
offset: num("Line offset (0-based, optional)"),
|
||||
limit: num("Max lines to return (optional)"),
|
||||
}, ["path"], ""),
|
||||
},
|
||||
{
|
||||
name: "file_write",
|
||||
description: "Write content to a file (create or overwrite)",
|
||||
inputSchema: obj({
|
||||
path: str("File path to write"),
|
||||
content: str("Content to write (text or base64)"),
|
||||
encoding: str("utf8 | base64 (default utf8)"),
|
||||
}, ["path", "content"], ""),
|
||||
},
|
||||
{
|
||||
name: "file_move",
|
||||
description: "Move or rename a file/directory",
|
||||
inputSchema: obj({
|
||||
from: str("Source path"),
|
||||
to: str("Destination path"),
|
||||
}, ["from", "to"], ""),
|
||||
},
|
||||
{
|
||||
name: "file_delete",
|
||||
description: "Delete a file or directory (recursive for dirs)",
|
||||
inputSchema: obj({
|
||||
path: str("Path to delete"),
|
||||
recursive: bool("Recursive delete for directories (default false)"),
|
||||
}, ["path"], ""),
|
||||
},
|
||||
{
|
||||
name: "file_stat",
|
||||
description: "Get file metadata (size, permissions, mtime)",
|
||||
inputSchema: obj({
|
||||
path: str("Path to stat"),
|
||||
}, ["path"], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 4: System Control (4 tools) ─────────────────────
|
||||
export const SYSTEM_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "sysinfo",
|
||||
description: "Get system resource usage (CPU%, RAM, disk, uptime, network IO)",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
{
|
||||
name: "power",
|
||||
description: "Power management: shutdown, reboot, sleep, lock",
|
||||
inputSchema: obj({
|
||||
action: str("shutdown | reboot | sleep | lock"),
|
||||
}, ["action"], ""),
|
||||
},
|
||||
{
|
||||
name: "service",
|
||||
description: "Manage system services/daemons (start/stop/restart/status)",
|
||||
inputSchema: obj({
|
||||
name: str("Service name"),
|
||||
action: str("start | stop | restart | status | enable | disable"),
|
||||
}, ["name", "action"], ""),
|
||||
},
|
||||
{
|
||||
name: "notify_send",
|
||||
description: "Send a desktop notification to the device",
|
||||
inputSchema: obj({
|
||||
title: str("Notification title"),
|
||||
message: str("Notification body"),
|
||||
urgency: str("low | normal | critical (default normal)"),
|
||||
}, ["title", "message"], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 5: Remote Desktop (4 tools) ─────────────────────
|
||||
export const REMOTE_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "screenshot",
|
||||
description: "Capture a screenshot of the device display",
|
||||
inputSchema: obj({
|
||||
display: num("Display index (default 0)"),
|
||||
format: str("png | jpg (default png)"),
|
||||
quality: num("JPEG quality 1-100 (default 80)"),
|
||||
}, [], ""),
|
||||
},
|
||||
{
|
||||
name: "remote_input",
|
||||
description: "Inject keyboard/mouse input events on the remote device",
|
||||
inputSchema: obj({
|
||||
type: str("key | mouse | text"),
|
||||
action: str("key: press/release; mouse: move/click/scroll; text: input string"),
|
||||
value: str("Key name, coordinates, or text content"),
|
||||
}, ["type", "action", "value"], ""),
|
||||
},
|
||||
{
|
||||
name: "clipboard_sync",
|
||||
description: "Read or write the device clipboard",
|
||||
inputSchema: obj({
|
||||
action: str("read | write"),
|
||||
content: str("Content to write (required for write action)"),
|
||||
}, ["action"], ""),
|
||||
},
|
||||
{
|
||||
name: "remote_stream",
|
||||
description: "Start/stop a low-latency screen streaming session",
|
||||
inputSchema: obj({
|
||||
action: str("start | stop"),
|
||||
fps: num("Frames per second (default 15)"),
|
||||
quality: num("Quality 1-100 (default 60)"),
|
||||
}, ["action"], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 6: AI Manipulation (4 tools) ────────────────────
|
||||
export const AI_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "ui_find",
|
||||
description: "Find UI elements by description (uses OCR/accessibility)",
|
||||
inputSchema: obj({
|
||||
query: str("Text or description to search for on screen"),
|
||||
confidence: num("Minimum confidence 0-1 (default 0.7)"),
|
||||
}, ["query"], ""),
|
||||
},
|
||||
{
|
||||
name: "ui_act",
|
||||
description: "Click, type, or scroll at a UI element found by ui_find",
|
||||
inputSchema: obj({
|
||||
element: str("Element descriptor from ui_find result"),
|
||||
action: str("click | dblclick | type | scroll | hover"),
|
||||
value: str("Text to type or scroll direction"),
|
||||
}, ["element", "action"], ""),
|
||||
},
|
||||
{
|
||||
name: "browser_open",
|
||||
description: "Open a URL in the default browser and optionally extract content",
|
||||
inputSchema: obj({
|
||||
url: str("URL to open"),
|
||||
extract: bool("Extract page text content after load (default false)"),
|
||||
}, ["url"], ""),
|
||||
},
|
||||
{
|
||||
name: "ocr_screen",
|
||||
description: "Run OCR on a screenshot region and return text results",
|
||||
inputSchema: obj({
|
||||
x: num("Region left (0-1 fraction of width, default 0)"),
|
||||
y: num("Region top (default 0)"),
|
||||
w: num("Region width (default 1)"),
|
||||
h: num("Region height (default 1)"),
|
||||
lang: str("Language code (default: eng)"),
|
||||
}, [], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 7: Network (3 tools) ─────────────────────────────
|
||||
export const NETWORK_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "net_info",
|
||||
description: "Get network interfaces, IPs, MAC addresses",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
{
|
||||
name: "net_ping",
|
||||
description: "Ping a host and return latency/packet loss",
|
||||
inputSchema: obj({
|
||||
host: str("Hostname or IP to ping"),
|
||||
count: num("Number of pings (default 4)"),
|
||||
}, ["host"], ""),
|
||||
},
|
||||
{
|
||||
name: "net_speedtest",
|
||||
description: "Run a basic network speed test (download/upload)",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 8: Hardware (3 tools) ────────────────────────────
|
||||
export const HARDWARE_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "hw_temperature",
|
||||
description: "Read CPU/GPU temperature sensors",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
{
|
||||
name: "hw_battery",
|
||||
description: "Get battery status (level, charging, health)",
|
||||
inputSchema: obj({}, [], "No input required"),
|
||||
},
|
||||
{
|
||||
name: "hw_sensors",
|
||||
description: "Read hardware sensors (fan speed, voltage, etc.)",
|
||||
inputSchema: obj({
|
||||
type: str("Filter by sensor type (optional)"),
|
||||
}, [], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 9: Developer Tools (2 tools) ─────────────────────
|
||||
export const DEV_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "dev_shell",
|
||||
description: "Open an interactive shell session (persistent, stateful)",
|
||||
inputSchema: obj({
|
||||
command: str("Shell command (empty to start session)"),
|
||||
}, ["command"], ""),
|
||||
},
|
||||
{
|
||||
name: "dev_eval",
|
||||
description: "Execute JavaScript/Python code snippet on the device and return result",
|
||||
inputSchema: obj({
|
||||
code: str("Code to execute"),
|
||||
lang: str("js | python (default js)"),
|
||||
}, ["code"], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Module 10: Media (1 tool) ──────────────────────────────
|
||||
export const MEDIA_TOOLS: ToolDef[] = [
|
||||
{
|
||||
name: "media_control",
|
||||
description: "Control media playback (play/pause/next/prev/volume)",
|
||||
inputSchema: obj({
|
||||
action: str("play | pause | next | prev | volume_up | volume_down | mute"),
|
||||
}, ["action"], ""),
|
||||
},
|
||||
];
|
||||
|
||||
// ── Aggregate ───────────────────────────────────────────────
|
||||
export const ALL_TOOLS: ToolCategory[] = [
|
||||
{ module: 1, name: "Device Management", tools: DEVICE_TOOLS },
|
||||
{ module: 2, name: "Command Execution", tools: EXEC_TOOLS },
|
||||
{ module: 3, name: "File Operations", tools: FILE_TOOLS },
|
||||
{ module: 4, name: "System Control", tools: SYSTEM_TOOLS },
|
||||
{ module: 5, name: "Remote Desktop", tools: REMOTE_TOOLS },
|
||||
{ module: 6, name: "AI Manipulation", tools: AI_TOOLS },
|
||||
{ module: 7, name: "Network", tools: NETWORK_TOOLS },
|
||||
{ module: 8, name: "Hardware", tools: HARDWARE_TOOLS },
|
||||
{ module: 9, name: "Developer Tools", tools: DEV_TOOLS },
|
||||
{ module: 10, name: "Media", tools: MEDIA_TOOLS },
|
||||
];
|
||||
|
||||
export const ALL_TOOL_DEFS: ToolDef[] = ALL_TOOLS.flatMap(c => c.tools);
|
||||
export const TOOL_COUNT = ALL_TOOL_DEFS.length; // 36
|
||||
|
||||
/** Look up a tool by name */
|
||||
export function getTool(name: string): ToolDef | undefined {
|
||||
return ALL_TOOL_DEFS.find(t => t.name === name);
|
||||
}
|
||||
Reference in New Issue
Block a user