MCP HubMCP Hub
스킬 목록으로 돌아가기

build-cli-plugin

pjt222
업데이트됨 6 days ago
25 조회
17
2
17
GitHub에서 보기
메타design

정보

이 스킬은 TypeScript의 추상 베이스 클래스를 사용하여 CLI 플러그인 또는 어댑터를 구축하는 패턴을 제공합니다. 플러그인 계약 정의, 멱등성 설치/제거 작업 구현, 설치 전략 선택 방법을 안내합니다. CLI 설치 도구에 프레임워크 지원을 추가하거나 다중 대상 도구용 플러그인 시스템을 생성할 때 활용하세요.

빠른 설치

Claude Code

추천
기본
npx skills add pjt222/agent-almanac -a claude-code
플러그인 명령대체
/plugin add https://github.com/pjt222/agent-almanac
Git 클론대체
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/build-cli-plugin

Claude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요

문서

建 CLI 之插件

以抽象基類之式加新插件或適配於 CLI 工具之可插架。

用時

  • 加新標框架於 CLI 裝器
  • 為多標之命行工具建插件系
  • 擴現有適配架以新策之變
  • 移內容之交於用異檔佈之框架

  • 必要:插件所支之框架或標(名、設路、規)
  • 必要:基類或插件契之路
  • 必要:裝略:symlinkcopyfile-per-item、或 append-to-file
  • 可選:插件所理之內容類(如只技、技加人、全支)
  • 可選:範支(項目級、全局、二者)

第一步:定契

基類立諸插件必施之介:

export class FrameworkAdapter {
  static id = 'base';            // Unique identifier
  static displayName = 'Base';   // Human-readable name
  static strategy = 'symlink';   // Installation strategy
  static contentTypes = ['skill']; // What this adapter handles

  async detect(projectDir) { return false; }
  getTargetPath(projectDir, scope) { throw new Error('Not implemented'); }
  async install(item, projectDir, scope, options) { throw new Error('Not implemented'); }
  async uninstall(item, projectDir, scope, options) { throw new Error('Not implemented'); }
  async listInstalled(projectDir, scope) { return []; }
  async audit(projectDir, scope) { return { framework: this.constructor.displayName, ok: [], warnings: [], errors: [] }; }
  supports(contentType) { return this.constructor.contentTypes.includes(contentType); }
}

靜態欄定插件之身與能:

  • id:用於 --framework <id> 選與果報
  • displayName:人讀之輸出所見
  • strategy:定內容達標之法
  • contentTypes:篩此適配所收之項

若基類未建,先建之。此式可擴至任數之插件。

得: 基類備,含靜身欄與抽象法。

敗則: 若基類有法不適諸插件(如諸框架未皆支 audit),供默實為合理之無作。

第二步:擇裝略

StrategyWhen to useExample
symlinkTarget reads source files directly. Cheapest, stays in sync.Claude Code reads .claude/skills/<name>/ symlinks
copyTarget needs files in its own directory. Modifications don't propagate.Some IDEs index only their own dirs
file-per-itemTarget expects one file per item with specific format.Cursor .mdc rules files
append-to-fileTarget reads a single instructions file.Aider CONVENTIONS.md, Codex AGENTS.md

略決施之形:

  • SymlinksymlinkSync(source, target) — 理相對與絕對之路
  • CopycpSync(source, target, { recursive: true }) — 理覆寫
  • File-per-itemwriteFileSync(target, transform(content)) — 或須格式轉
  • Append-to-file:以標裹內容以冪等插/換/刪

得: 已擇略,附清由,據標框架如何察內容。

敗則: 若不定,察框架之文如何察設或指檔。若框架讀任目,默為 symlink。

第三步:施察

察告 CLI 項目中何框架存:

// In detector.js — each rule checks for a filesystem marker
const RULES = [
  {
    id: 'my-framework',
    displayName: 'My Framework',
    check: (dir) => existsSync(resolve(dir, '.myframework/')),
    marker: '.myframework/',
    scope: 'project',
  },
];

察之略:

  • 目存.claude/.cursor/.gemini/
  • 設檔opencode.json.aider.conf.yml
  • 指檔AGENTS.mdCONVENTIONS.md
  • 全局標~/.openclaw/~/.hermes/

恆於察果中返標,令用者知框架何以被察。

得: 察律穩識框架而無誤報。

敗則: 若框架無獨標(泛目名),合諸標用之,或須明之 --framework 指。

第四步:施裝,帶冪等

async install(item, projectDir, scope, options) {
  const targetDir = this.getTargetPath(projectDir, scope);
  const targetPath = resolve(targetDir, item.id);

  // Idempotency: skip if already installed (unless force)
  if (existsSync(targetPath) && !options.force) {
    return { action: 'skipped', path: targetPath };
  }

  if (options.dryRun) {
    return { action: 'created', path: targetPath, details: 'dry-run' };
  }

  // Ensure parent directory exists
  mkdirSync(targetDir, { recursive: true });

  // Strategy-specific installation
  if (this.constructor.strategy === 'symlink') {
    const relPath = relative(targetDir, item.sourceDir);
    symlinkSync(relPath, targetPath);
  } else if (this.constructor.strategy === 'copy') {
    cpSync(item.sourceDir, targetPath, { recursive: true });
  }

  return { action: 'created', path: targetPath };
}

冪等之律:

  • 標存且未 --force
  • --force(先刪而後裝)
  • 乾行:恆成功,返 action: 'created'
  • 返值:恆為 { action, path, details? }

得: 裝於標路建內容,若存則略,敬 --force--dry-run

敗則: Windows/NTFS 上 symlink 建敗者,降為目 junction 或 copy。記降級。

第五步:施卸,帶清

async uninstall(item, projectDir, scope, options) {
  const targetDir = this.getTargetPath(projectDir, scope);
  const targetPath = resolve(targetDir, item.id);

  if (!existsSync(targetPath)) {
    return { action: 'skipped', path: targetPath };
  }

  if (options.dryRun) {
    return { action: 'removed', path: targetPath };
  }

  // Remove the installed content
  rmSync(targetPath, { recursive: true });

  return { action: 'removed', path: targetPath };
}

清之考:

  • 只刪插件所裝者——勿刪用者所作之檔
  • append-to-file:刪標區,非全檔
  • 留父目(他插件或用之)

得: 卸只刪插件之內容,他無損。

敗則: 若刪敗(權、鎖),返錯果而非拋。

第六步:施列與察

async listInstalled(projectDir, scope) {
  const targetDir = this.getTargetPath(projectDir, scope);
  if (!existsSync(targetDir)) return [];

  const entries = readdirSync(targetDir);
  return entries.map(name => {
    const fullPath = resolve(targetDir, name);
    const broken = lstatSync(fullPath).isSymbolicLink()
      && !existsSync(fullPath);
    return { id: name, type: 'skill', broken };
  });
}

async audit(projectDir, scope) {
  const items = await this.listInstalled(projectDir, scope);
  const ok = items.filter(i => !i.broken);
  const broken = items.filter(i => i.broken);
  return {
    framework: this.constructor.displayName,
    ok: [`${ok.length} skills installed`],
    warnings: [],
    errors: broken.map(i => `Broken: ${i.id}`),
  };
}

得: 列返諸裝項,含斷鏈之察。察總其康。

敗則: 若標目不存,返空果(非錯——乃框架未裝)。

第七步:註插件

// In adapters/index.js
import { MyFrameworkAdapter } from './my-framework.js';
register(MyFrameworkAdapter);

註令適配可用於:

  • 自動察(detectFrameworks()getAdaptersForDetections()
  • 明擇(--framework my-framework
  • 列(listAdapters()

得: 適配見於 tool detect 之輸出,可以 --framework 指之。

敗則: 若適配不現,驗 static id 合察律之 idregister() 已呼。

第八步:書測

describe('adapter: my-framework (dry-run)', () => {
  it('targets the correct path', () => {
    const out = run('install create-skill --framework my-framework --dry-run');
    assert.match(out, /\.myframework/i);
  });
});

至少測:乾行之路、察之存、內容類之支。

得: 適配特測證裝之路與行。

敗則: CI 中無標目而框架不察者,測中明用 --framework

  • 插件正擴基類
  • 靜欄(iddisplayNamestrategycontentTypes)已設
  • 察律識框架而無誤報
  • install() 冪等(若存則略,敬 --force
  • uninstall() 只刪插件所建者
  • listInstalled() 察斷 symlink
  • audit() 準報康
  • 插件已註,現於 tool detect
  • 乾行測過

  • 忘相對與絕對 symlink:項目範之 symlink 宜相對(可攜)。全範之 symlink 宜絕對(不依 cwd)
  • 未理缺父目:恆 mkdirSync(dir, { recursive: true }) 於建內容前
  • append-to-file 無標:無冪等標(<!-- start:id --> / <!-- end:id -->),反覆裝重內容。恆以標裹附之內容
  • 察誤報:泛目名(如 .config/)或合多框架。用目內之特檔標
  • supports():裝器於派前呼 supports(item.type)。若 contentTypes 誤,適配默略項

  • scaffold-cli-command — 建用此插件之 CLI 命
  • test-cli-application — CLI 工具之測模式,含適配測
  • design-cli-output — 裝卸果之終端輸出

GitHub 저장소

pjt222/agent-almanac
경로: i18n/wenyan/skills/build-cli-plugin
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

연관 스킬

content-collections

메타

이 스킬은 콘텐츠 콜렉션(Content Collections)을 위한 프로덕션 검증된 설정을 제공합니다. 콘텐츠 콜렉션은 Markdown/MDX 파일을 Zod 검증이 포함된 타입 안전한 데이터 콜렉션으로 변환해주는 TypeScript 최우선 도구입니다. 블로그, 문서 사이트 또는 콘텐츠 중심의 Vite + React 애플리케이션을 구축할 때 타입 안전성과 자동 콘텐츠 검증을 보장하기 위해 사용하세요. Vite 플러그인 구성과 MDX 컴파일부터 배포 최적화 및 스키마 검증에 이르기까지 모든 것을 다룹니다.

스킬 보기

polymarket

메타

이 스킬은 개발자들이 Polymarket 예측 시장 플랫폼을 활용한 애플리케이션을 구축할 수 있도록 지원하며, 거래 및 시장 데이터를 위한 API 통합 기능을 포함합니다. 또한 WebSocket을 통한 실시간 데이터 스트리밍을 제공하여 실시간 거래와 시장 활동을 모니터링할 수 있습니다. 이를 통해 거래 전략을 구현하거나 실시간 시장 업데이트를 처리하는 도구를 생성하는 데 활용할 수 있습니다.

스킬 보기

creating-opencode-plugins

메타

이 스킬은 개발자들이 명령어, 파일, LSP 작업 등 25개 이상의 이벤트 유형에 연결되는 OpenCode 플러그인을 만들 수 있도록 돕습니다. JavaScript/TypeScript 모듈을 위한 플러그인 구조, 이벤트 API 명세, 구현 패턴을 제공합니다. OpenCode AI 어시스턴트의 라이프사이클을 사용자 정의 이벤트 기반 로직으로 가로채거나, 모니터링하거나, 확장해야 할 때 사용하세요.

스킬 보기

sglang

메타

SGLang은 RadixAttention 프리픽스 캐싱을 활용하여 JSON, 정규식, 에이전트 워크플로우를 위한 고속 구조화 생성에 특화된 고성능 LLM 서빙 프레임워크입니다. 특히 반복되는 프리픽스가 있는 작업에서 상당히 빠른 추론 속도를 제공하여 복잡한 구조화 출력 및 다중 턴 대화에 이상적입니다. 제약 디코딩이 필요하거나 광범위한 프리픽스 공유가 있는 애플리케이션을 구축할 때는 vLLM과 같은 대안보다 SGLang을 선택하십시오.

스킬 보기