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.1001
Version published
Weekly downloads
1.4K
-48.54%
Maintainers
1
Weekly downloads
 
Created
Source

@cmdop/node

CMDOP SDK

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
await client.terminal.setMachine('my-server');
const { output, exitCode } = await client.terminal.execute('echo hello');
console.log(output, exitCode);

// Get the currently active session
const active = await client.terminal.getActiveSession({ hostname: 'my-server' });

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

// Attach to session (bidirectional gRPC stream, SSH-like)
const attach = client.terminal.attach(session.sessionId, { cols: 120, rows: 40 });
attach.on((event) => {
  if (event.type === 'sessionReady') console.log('Connected!');
  if (event.type === 'output') process.stdout.write(event.data);
  if (event.type === 'closed') console.log('Disconnected:', event.reason);
});
await attach.connect();
attach.sendInput('ls -la\n');
attach.sendResize(200, 50);
attach.close();

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

SSH Connect

High-level interactive terminal (like ssh). Handles raw mode, stdin/stdout piping, resize, and Ctrl+D to disconnect.

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

const client = CMDOPClient.remote('cmdop_live_xxx');
const exitCode = await sshConnect({
  client,
  hostname: 'my-server',
  debug: false,       // optional: log gRPC messages to stderr
  sessionId: '...',   // optional: skip session discovery
});
process.exit(exitCode);

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'
  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' } } })
);

Remote Connections

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

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,
  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

cmdok CLI

No code needed? Use the standalone binary:

curl -fsSL cmdop.com/install-cli.sh | bash
cmdok ssh

cmdok ssh

License

MIT

Keywords

cmdop

FAQs

Package last updated on 10 Mar 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