smithery.ai

developer-tools

CLI tools, SDKs, and developer experience patterns

First seen Mar 29, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 11,090 B
  • docs SUMMARY.md 73 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Developer Tools

Overview

Building command-line interfaces, SDKs, and tools that enhance developer experience.


CLI Development

CLI Framework (Commander)

#!/usr/bin/env node
import { Command } from 'commander';
import chalk from 'chalk';
import ora from 'ora';
import inquirer from 'inquirer';

const program = new Command();

program
  .name('myctl')
  .description('CLI tool for managing resources')
  .version('1.0.0');

// Simple command
program
  .command('init')
  .description('Initialize a new project')
  .option('-t, --template <name>', 'Template to use', 'default')
  .option('-d, --directory <path>', 'Target directory', '.')
  .action(async (options) => {
    const spinner = ora('Initializing project...').start();

    try {
      await initProject(options.template, options.directory);
      spinner.succeed(chalk.green('Project initialized successfully!'));
    } catch (error) {
      spinner.fail(chalk.red(`Failed: ${error.message}`));
      process.exit(1);
    }
  });

// Interactive command
program
  .command('create <name>')
  .description('Create a new resource')
  .action(async (name) => {
    const answers = await inquirer.prompt([
      {
        type: 'list',
        name: 'type',
        message: 'Select resource type:',
        choices: ['api', 'worker', 'database'],
      },
      {
        type: 'input',
        name: 'description',
        message: 'Description:',
      },
      {
        type: 'confirm',
        name: 'public',
        message: 'Make it public?',
        default: false,
      },
    ]);

    await createResource(name, answers);
    console.log(chalk.green(`Created ${answers.type}: ${name}`));
  });

// Subcommands
const configCmd = program.command('config').description('Manage configuration');

configCmd
  .command('set <key> <value>')
  .description('Set a config value')
  .action(async (key, value) => {
    await setConfig(key, value);
    console.log(`Set ${key}=${value}`);
  });

configCmd
  .command('get <key>')
  .description('Get a config value')
  .action(async (key) => {
    const value = await getConfig(key);
    console.log(value);
  });

configCmd
  .command('list')
  .description('List all config values')
  .action(async () => {
    const config = await getAllConfig();
    console.table(config);
  });

// Global options
program
  .option('--debug', 'Enable debug mode')
  .option('--json', 'Output as JSON')
  .hook('preAction', (thisCommand) => {
    if (thisCommand.opts().debug) {
      process.env.DEBUG = 'true';
    }
  });

program.parse();

CLI Output Formatting

import Table from 'cli-table3';
import boxen from 'boxen';

// Table output
function printTable(data: Array<Record<string, any>>, columns: string[]) {
  const table = new Table({
    head: columns.map((c) => chalk.bold(c)),
    style: { head: ['cyan'] },
  });

  data.forEach((row) => {
    table.push(columns.map((col) => row[col] ?? ''));
  });

  console.log(table.toString());
}

// JSON output
function printJson(data: any) {
  console.log(JSON.stringify(data, null, 2));
}

// Box output
function printBox(message: string, title?: string) {
  console.log(
    boxen(message, {
      padding: 1,
      margin: 1,
      borderStyle: 'round',
      title,
      titleAlignment: 'center',
    })
  );
}

// Progress bar
import cliProgress from 'cli-progress';

async function withProgress<T>(
  items: T[],
  fn: (item: T) => Promise<void>,
  label: string
) {
  const bar = new cliProgress.SingleBar({
    format: `${label} |{bar}| {percentage}% | {value}/{total}`,
    barCompleteChar: '\u2588',
    barIncompleteChar: '\u2591',
  });

  bar.start(items.length, 0);

  for (const item of items) {
    await fn(item);
    bar.increment();
  }

  bar.stop();
}

SDK Development

TypeScript SDK

// sdk/index.ts
export class MyServiceClient {
  private baseUrl: string;
  private apiKey: string;

  constructor(options: { apiKey: string; baseUrl?: string }) {
    this.apiKey = options.apiKey;
    this.baseUrl = options.baseUrl || 'https://api.example.com';
  }

  private async request<T>(
    method: string,
    path: string,
    data?: any
  ): Promise<T> {
    const response = await fetch(`${this.baseUrl}${path}`, {
      method,
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${this.apiKey}`,
      },
      body: data ? JSON.stringify(data) : undefined,
    });

    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      throw new ApiError(response.status, error.message || 'Request failed');
    }

    return response.json();
  }

  // Resource: Users
  users = {
    list: (params?: ListUsersParams) =>
      this.request<PaginatedResponse<User>>('GET', '/users?' + qs(params)),

    get: (id: string) => this.request<User>('GET', `/users/${id}`),

    create: (data: CreateUserInput) =>
      this.request<User>('POST', '/users', data),

    update: (id: string, data: UpdateUserInput) =>
      this.request<User>('PUT', `/users/${id}`, data),

    delete: (id: string) => this.request<void>('DELETE', `/users/${id}`),
  };

  // Resource: Projects
  projects = {
    list: () => this.request<Project[]>('GET', '/projects'),
    get: (id: string) => this.request<Project>('GET', `/projects/${id}`),
    create: (data: CreateProjectInput) =>
      this.request<Project>('POST', '/projects', data),
  };
}

// Error class
export class ApiError extends Error {
  constructor(
    public status: number,
    message: string,
    public code?: string
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

// Types
export interface User {
  id: string;
  email: string;
  name: string;
  createdAt: string;
}

export interface CreateUserInput {
  email: string;
  name: string;
}

export interface UpdateUserInput {
  name?: string;
}

export interface PaginatedResponse<T> {
  data: T[];
  meta: {
    page: number;
    limit: number;
    total: number;
  };
}

// Usage
const client = new MyServiceClient({ apiKey: 'sk_...' });

const users = await client.users.list({ page: 1, limit: 10 });
const user = await client.users.create({ email: '[email protected]', name: 'Test' });

SDK with Retry and Rate Limiting

import pRetry from 'p-retry';
import pThrottle from 'p-throttle';

class RobustClient {
  private throttle = pThrottle({
    limit: 100,
    interval: 60000, // 100 requests per minute
  });

  private async requestWithRetry<T>(
    fn: () => Promise<T>,
    options?: { retries?: number }
  ): Promise<T> {
    return pRetry(
      async () => {
        try {
          return await fn();
        } catch (error) {
          if (error instanceof ApiError) {
            // Don't retry client errors
            if (error.status >= 400 && error.status < 500) {
              throw new pRetry.AbortError(error);
            }
          }
          throw error;
        }
      },
      {
        retries: options?.retries ?? 3,
        onFailedAttempt: (error) => {
          console.log(
            `Attempt ${error.attemptNumber} failed. ${error.retriesLeft} retries left.`
          );
        },
      }
    );
  }

  private request = this.throttle(async <T>(
    method: string,
    path: string,
    data?: any
  ): Promise<T> => {
    return this.requestWithRetry(async () => {
      const response = await fetch(`${this.baseUrl}${path}`, {
        method,
        headers: this.getHeaders(),
        body: data ? JSON.stringify(data) : undefined,
      });

      // Handle rate limiting
      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After');
        const delay = retryAfter ? parseInt(retryAfter) * 1000 : 60000;
        await sleep(delay);
        throw new Error('Rate limited, retrying...');
      }

      if (!response.ok) {
        throw new ApiError(response.status, await response.text());
      }

      return response.json();
    });
  });
}

API Documentation

OpenAPI Spec Generation

import { generateOpenApi } from '@ts-rest/open-api';
import { contract } from './contract';

const openApiDocument = generateOpenApi(contract, {
  info: {
    title: 'My API',
    version: '1.0.0',
    description: 'API for managing resources',
  },
  servers: [
    { url: 'https://api.example.com', description: 'Production' },
    { url: 'https://staging-api.example.com', description: 'Staging' },
  ],
});

// Export for documentation tools
export { openApiDocument };

Interactive Documentation

// Using Swagger UI React
import SwaggerUI from 'swagger-ui-react';
import 'swagger-ui-react/swagger-ui.css';

function ApiDocs() {
  return (
    <SwaggerUI
      url="/api/openapi.json"
      docExpansion="list"
      defaultModelsExpandDepth={3}
    />
  );
}

// Or Redoc
import { RedocStandalone } from 'redoc';

function ApiDocs() {
  return <RedocStandalone specUrl="/api/openapi.json" />;
}

Developer Portal

// API key management component
function ApiKeyManager() {
  const [keys, setKeys] = useState<ApiKey[]>([]);

  async function createKey(name: string) {
    const key = await api.createApiKey({ name });
    // Show the secret only once
    showModal({
      title: 'API Key Created',
      content: (
        <div>
          <p>Save this key - it won't be shown again:</p>
          <code className="bg-gray-100 p-2 block">{key.secret}</code>
        </div>
      ),
    });
    setKeys([...keys, key]);
  }

  async function revokeKey(keyId: string) {
    await api.revokeApiKey(keyId);
    setKeys(keys.filter((k) => k.id !== keyId));
  }

  return (
    <div>
      <h2>API Keys</h2>
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Created</th>
            <th>Last Used</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
          {keys.map((key) => (
            <tr key={key.id}>
              <td>{key.name}</td>
              <td>{formatDate(key.createdAt)}</td>
              <td>{key.lastUsedAt ? formatDate(key.lastUsedAt) : 'Never'}</td>
              <td>
                <button onClick={() => revokeKey(key.id)}>Revoke</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <button onClick={() => createKey(prompt('Key name:') || 'Unnamed')}>
        Create New Key
      </button>
    </div>
  );
}

Related Skills

  • [[api-design]] - API design patterns
  • [[documentation]] - Technical writing
  • [[automation-scripts]] - Build automation