You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@cmdop/node

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cmdop/node

CMDOP SDK for Node.js - Server-side agent interaction via gRPC

Source
npmnpm
Version
2026.3.101
Version published
Weekly downloads
1.4K
-48.54%
Maintainers
1
Weekly downloads
 
Created
Source

@cmdop/node

Node.js SDK for CMDOP agent interaction via gRPC.

Installation

npm install @cmdop/node
# or
pnpm add @cmdop/node

Requirements: Node.js >= 18.0.0

Quick Start

import { CMDOPClient } from '@cmdop/node';

// Local connection (auto-discover agent via ~/.cmdop/agent.info)
const client = CMDOPClient.local();

// Remote connection via cloud relay
const client = CMDOPClient.remote('cmdop_live_xxx');

// Auto-detect: local first, falls back to CMDOP_API_KEY env var
const client = await CMDOPClient.discover();

// Automatic cleanup via Symbol.asyncDispose (TypeScript 5.2+)
await using client = CMDOPClient.local();

Services

Terminal

// Create a session
const session = await client.terminal.create({ cols: 120, rows: 40 });

// Send input / resize / signal
await client.terminal.sendInput(session.sessionId, 'ls -la\n');
await client.terminal.resize(session.sessionId, 200, 50);
await client.terminal.signal(session.sessionId, 'SIGINT');

// Run command and wait for output
const output = await client.terminal.execute(session.sessionId, 'echo hello');
console.log(output.stdout, output.exitCode);

// Get the currently active session
const active = await client.terminal.getActiveSession();

// Stream output in real-time
const stream = client.terminal.stream(session.sessionId);
stream.on((event) => {
  if (event.type === 'output') process.stdout.write(event.data.toString());
});
await stream.start();

// List / close
const { sessions } = await client.terminal.list();
await client.terminal.close(session.sessionId);

Files

// List directory
const result = await client.files.list('/tmp', { pageSize: 50 });
for (const entry of result.entries) {
  console.log(entry.name, entry.type, entry.size);
}

// Read / Write
const file = await client.files.read('/tmp/file.txt');
console.log(file.content.toString('utf-8'));
await client.files.write('/tmp/new.txt', 'Hello World');

// Stat / Mkdir / Move / Copy / Delete
await client.files.stat('/tmp/file.txt');
await client.files.mkdir('/tmp/newdir');
await client.files.move('/tmp/a.txt', '/tmp/b.txt');
await client.files.copy('/tmp/src.txt', '/tmp/dst.txt');
await client.files.delete('/tmp/file.txt');

// Search / Archive
const matches = await client.files.search('/tmp', { pattern: '*.log' });
await client.files.archive(['/tmp/dir'], '/tmp/out.zip');

Download

Transfer files from the remote agent to local disk.

// Download a remote file
const result = await client.download.downloadFile('/remote/data.csv', '/local/data.csv');
console.log(`Saved ${result.size} bytes in ${result.metrics?.durationMs}ms`);

// Download a URL via the agent (respects agent cookies/auth)
const result = await client.download.downloadUrl(
  'https://example.com/report.pdf',
  '/local/report.pdf'
);

Agent

// One-shot execution
const result = await client.agent.run('List files in /tmp', {
  mode: 'terminal', // 'chat' | 'terminal' | 'command' | 'router' | 'planner' | 'browser' | 'scraper' | 'form_filler'
  timeoutSeconds: 60,
  maxTurns: 10,
  maxRetries: 2,
  model: 'claude-opus-4-6',
});
console.log(result.text);
console.log(result.usage?.totalTokens);
console.log(result.toolResults);

// Streaming
const stream = client.agent.stream('Explain what ls -la does');
stream.on((event) => {
  if (event.type === 'token')      process.stdout.write(event.token);
  if (event.type === 'tool_start') console.log(`\n[tool: ${event.payload}]`);
  if (event.type === 'thinking')   console.log(`[thinking: ${event.payload}]`);
});
const result = await stream.start();
stream.cancel(); // cancel if needed

// Structured output
import { z, zodToJsonSchema } from '@cmdop/node';

const FileListSchema = z.object({
  files: z.array(z.string()),
  total: z.number(),
});

const data = await client.agent.extract<z.infer<typeof FileListSchema>>(
  'List files in /tmp',
  zodToJsonSchema(FileListSchema)
);
console.log(data.files, data.total);

Skills

// List all installed skills
const skills = await client.skills.list();
for (const skill of skills) {
  console.log(`${skill.name} (${skill.origin}) — ${skill.description}`);
}

// Show skill details
const detail = await client.skills.show('code-review');
if (detail.found) {
  console.log(detail.info?.name, detail.info?.version);
  console.log(detail.content); // SKILL.md body
  console.log(detail.source);  // file path on agent
}

// Run a skill
const result = await client.skills.run('code-review', 'Review my PR changes');
console.log(result.text);
console.log(result.durationMs);

// Structured output
import { z, zodToJsonSchema } from '@cmdop/node';

const ReviewSchema = z.object({
  issues: z.array(z.object({ file: z.string(), line: z.number(), message: z.string() })),
  summary: z.string(),
});

const review = await client.skills.extract<z.infer<typeof ReviewSchema>>(
  'code-review',
  'Review the changes',
  zodToJsonSchema(ReviewSchema)
);
console.log(review.issues, review.summary);

Extract

Dedicated structured data extraction RPC (more reliable than agent.extract()).

import { z } from '@cmdop/node';

const ConfigSchema = z.object({
  host: z.string(),
  port: z.number(),
  database: z.string(),
});

// Zod schema — result is validated and fully typed
const result = await client.extract.runSchema(
  'Find the database config in config files',
  ConfigSchema
);
console.log(result.data.host);
console.log(result.reasoning);
console.log(result.metrics?.durationMs);

// Raw JSON Schema
const raw = await client.extract.run<{ host: string }>(
  'Find the database host',
  JSON.stringify({ type: 'object', properties: { host: { type: 'string' } } })
);

Browser

// Create a session
const browser = await client.browser.createSession({
  startUrl: 'https://example.com',
  headless: true,
});

// Navigation
await browser.navigate('https://github.com');
await browser.reload();
await browser.goBack();
await browser.goForward();

// Interaction
await browser.click({ selector: 'button.submit' });
await browser.type('hello world', 'input[name="q"]');
await browser.key('Enter');
await browser.hover('nav a.menu');
await browser.mouseMove(100, 200);

// Scroll
await browser.scrollDown(500);
await browser.scrollUp(500);
await browser.scrollToBottom();
await browser.scrollToTop();

// Wait
await browser.wait({ selector: '.loaded', timeoutMs: 5000 });
await browser.wait({ timeMs: 1000 });

// Read content
const html  = await browser.getHTML('main');
const text  = await browser.getText('h1');
const state = await browser.getState();     // url, title, scrollY, ...
const info  = await browser.getPageInfo();  // url, title, pageHeight, isHttps, cloudflareDetected, ...

// Extract structured data
const values = await browser.extract('a', { attribute: 'href' });
const data   = await browser.extractData({
  fields: [
    { name: 'title', selector: 'h1',     type: 'text' },
    { name: 'price', selector: '.price', type: 'text' },
  ],
});

// Screenshot (returns Buffer)
const screenshot = await browser.screenshot({ fullPage: true });

// Fetch (runs inside browser context, respects cookies)
const json = await browser.fetchJson<{ id: number }>('/api/me');
const html = await browser.fetchText('https://example.com/page');

// Cookies
const cookies = await browser.getCookies({ domain: 'example.com' });
await browser.setCookies([{ name: 'session', value: 'abc', domain: 'example.com' }]);

// Validate selectors
const valid = await browser.validateSelectors({ selectors: ['h1', '.missing'] });

// Network capture
await browser.networkEnable();
const exchanges = await browser.networkGetExchanges({ urlPattern: '/api/' });
const last      = await browser.networkGetLast('/api/user');
const stats     = await browser.networkStats();
const har       = await browser.networkExportHAR();
await browser.networkClear();
await browser.networkDisable();

// Cleanup
await browser.close();

// Or with Symbol.asyncDispose
await using browser = await client.browser.createSession({ startUrl: 'https://example.com' });

Remote Connections

For cloud relay connections, set the session ID before using files, agent, extract, or browser.

const client = CMDOPClient.remote('cmdop_live_xxx');

// Discover available agents
const agents = await CMDOPClient.listAgents('cmdop_live_xxx');
const online = await CMDOPClient.getOnlineAgents('cmdop_live_xxx');

// Route all services to a specific agent
client.setSessionId(online[0].agentId);

// Or route each service to a different machine
await client.files.setMachine('storage-01');
await client.agent.setMachine('gpu-box');
await client.skills.setMachine('gpu-box');
await client.terminal.setMachine('prod-01');

Client Properties

const client = CMDOPClient.remote('cmdop_live_xxx');

client.mode        // 'local' | 'remote'
client.address     // 'grpc.cmdop.com:443'
client.isConnected // false (lazy connection)
client.transport   // underlying BaseTransport instance

// Build client from a pre-configured transport
import { RemoteTransport } from '@cmdop/node';
const transport = new RemoteTransport({ apiKey: '...', server: 'custom.host:443' });
const client = CMDOPClient.fromTransport(transport);

Configuration

import { configure } from '@cmdop/node';

configure({
  connectTimeoutMs: 10_000,
  requestTimeoutMs: 30_000,
  retryAttempts: 5,
  retryTimeoutMs: 30_000,
  keepaliveIntervalMs: 25_000,
  circuitBreakerFailMax: 5,
  circuitBreakerResetMs: 30_000,
  maxMessageSize: 64 * 1024 * 1024,
  grpcServer: 'grpc.cmdop.com:443',
  apiBaseUrl: 'https://api.cmdop.com',
  logLevel: 'info',
  logJson: false,
});

Environment variables:

VariableDefaultDescription
CMDOP_GRPC_SERVERgrpc.cmdop.com:443gRPC server address
CMDOP_API_BASE_URLhttps://api.cmdop.comREST API base URL
CMDOP_CONNECT_TIMEOUT_MS10000Connection timeout (ms)
CMDOP_REQUEST_TIMEOUT_MS30000Per-request timeout (ms)
CMDOP_RETRY_ATTEMPTS5Max retry attempts
CMDOP_RETRY_TIMEOUT_MS30000Total retry window (ms)
CMDOP_KEEPALIVE_INTERVAL_MS25000Keepalive ping interval (ms)
CMDOP_QUEUE_MAX_SIZE1000Max streaming queue size
CMDOP_CIRCUIT_FAIL_MAX5Circuit breaker failure threshold
CMDOP_CIRCUIT_RESET_TIMEOUT_MS30000Circuit breaker reset time (ms)
CMDOP_MAX_MESSAGE_SIZE33554432Max gRPC message size (bytes)
CMDOP_LOG_LEVELinfodebug|info|warn|error|silent
CMDOP_LOG_JSONfalseStructured JSON logging
CMDOP_API_KEYAPI key (used by CMDOPClient.discover())

Error Handling

import {
  CMDOPError,
  // Core
  ConnectionError,
  AuthenticationError,
  SessionError,
  TimeoutError,
  NotFoundError,
  PermissionError,
  // Extended (Node SDK)
  AgentNotRunningError,
  StalePortFileError,
  ConnectionLostError,
  InvalidAPIKeyError,
  TokenExpiredError,
  AgentError,
  AgentOfflineError,
  AgentBusyError,
  FeatureNotAvailableError,
  SessionInterruptedError,
  FileTooLargeError,
  BrowserError,
  BrowserSessionClosedError,
  BrowserNavigationError,
  BrowserElementNotFoundError,
  RateLimitError,
} from '@cmdop/node';

try {
  await client.files.read('/etc/shadow');
} catch (error) {
  if (error instanceof PermissionError)        console.log('Permission denied');
  else if (error instanceof NotFoundError)     console.log('File not found');
  else if (error instanceof AgentOfflineError) console.log('Agent is offline');
  else if (error instanceof RateLimitError)    console.log('Rate limit exceeded');
  else if (error instanceof CMDOPError)        console.log(error.message);
}
  • @cmdop/core — Shared types and errors
  • @cmdop/react — React hooks

License

MIT

Keywords

cmdop

FAQs

Package last updated on 28 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts