mcpField
E
eve-app-cli

eve-app-cli

github.com/incept5開発0162 回インストール17 週間前に更新
リポジトリ

eve-app-cli について

Eve 対応アプリ向けのドメイン特化 CLI の構築方法を説明するスキルです。開発者がエージェントにコマンド経由でアプリ API を利用させるための、コマンド設計、出力、認証、配布の指針を示します。

主な機能

  1. 01ドメインに沿ったコマンド設計
  2. 02環境変数によるAPI認証
  3. 03人間向け表示とJSON出力
  4. 04段階的なコマンドヘルプ
  5. 05単体ファイルまたはイメージでの配布

活用シーン

  1. 01エージェント向けアプリCLIの構築
  2. 02生のRESTリクエストをコマンドに置き換え
  3. 03Eveジョブ用CLIのパッケージ化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/incept5/eve-skillpacks --skill eve-app-cli

インストール後、Claude Code で/eve-app-cliを入力して読み込まれたか確認します。

詳細

Eve App CLI

Eve 対応アプリ向けのドメイン固有 CLI を構築し、エージェントが生の REST 呼び出しではなくコマンドを使って操作できるようにします。

理由

エージェントは REST を操作するたびに、URL の組み立て、JSON の引用符処理、認証ヘッダー、エラーの解析に 3〜5 回の LLM 呼び出しを費やします。CLI を使えば、これを 1 回に減らせます。

# Before (3-5 calls, error-prone)
curl -X POST "$EVE_APP_API_URL_API/projects/$PID/changesets" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EVE_JOB_TOKEN" \
  -d @/tmp/changeset.json

# After (1 call, self-documenting)
eden changeset create --project $PID --file /tmp/changeset.json

クイックスタート

1. CLI パッケージを作成する
your-app/
  cli/
    src/
      index.ts          # Entry point
      client.ts         # API client (reads env vars)
      commands/
        projects.ts     # Domain commands
    bin/
      your-app          # Built artifact (single-file bundle)
    package.json
    tsconfig.json
2. API クライアントを実装する
// cli/src/client.ts — Copy this, change SERVICE name
const SERVICE = 'API';

export function getApiUrl(): string {
  const url = process.env[`EVE_APP_API_URL_${SERVICE}`];
  if (!url) {
    console.error(`Error: EVE_APP_API_URL_${SERVICE} not set.`);
    console.error('Are you running inside an Eve job with with_apis: [api]?');
    process.exit(1);
  }
  return url;
}

export async function api<T = unknown>(
  method: string,
  path: string,
  body?: unknown,
): Promise<T> {
  const url = getApiUrl();
  const token = process.env.EVE_JOB_TOKEN;
  const res = await fetch(`${url}${path}`, {
    method,
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!res.ok) {
    const err = await res.json().catch(() => ({} as Record<string, string>));
    console.error(`${method} ${path} → ${res.status}: ${err.message || res.statusText}`);
    process.exit(1);
  }
  return res.json() as Promise<T>;
}
3. コマンドを定義する
// cli/src/index.ts
import { Command } from 'commander';
import { api } from './client.js';
import { readFile } from 'node:fs/promises';

const program = new Command();
program.name('myapp').description('My App CLI').version('1.0.0');

program.command('items')
  .command('list')
  .option('--json', 'JSON output')
  .action(async (opts) => {
    const items = await api('GET', '/items');
    if (opts.json) return console.log(JSON.stringify(items, null, 2));
    for (const i of items) console.log(`${i.id}  ${i.name}`);
  });

program.command('items')
  .command('create')
  .requiredOption('--file <path>', 'JSON file')
  .action(async (opts) => {
    const body = JSON.parse(await readFile(opts.file, 'utf8'));
    const result = await api('POST', '/items', body);
    console.log(`Created: ${result.id}`);
  });

program.parse();
4. 依存関係なしで配布できるようにバンドルする

ビルドスクリプト(cli/build.mjs)を作成します。

import { build } from 'esbuild';
import { readFile, writeFile, chmod } from 'node:fs/promises';

await build({
  entryPoints: ['cli/src/index.ts'],
  bundle: true,
  platform: 'node',
  target: 'node20',
  format: 'cjs',          // CJS — commander uses require() internally
  outfile: 'cli/bin/myapp',
});

// Prepend shebang (esbuild banner escapes the !)
const code = await readFile('cli/bin/myapp', 'utf8');
await writeFile('cli/bin/myapp', '#!/usr/bin/env node\n' + code);
await chmod('cli/bin/myapp', 0o755);

package.json に追加します。

{
  "scripts": {
    "build": "node build.mjs"
  }
}

重要: package.json に "type": "module" を設定しないでください。実行時に require() エラーが発生します。代わりに、ビルドスクリプトには .mjs 拡張子を使用してください。

5. マニフェストで宣言する
# .eve/manifest.yaml
services:
  api:
    build:
      context: ./apps/api
    ports: [3000]
    x-eve:
      api_spec:
        type: openapi
      cli:
        name: myapp           # Binary name on $PATH
        bin: cli/bin/myapp     # Path relative to repo root

プラットフォームは、with_apis: [api] を指定したエージェントが CLI を利用できるように自動設定します。

設計ルール

コマンド構成

CLI コマンドは HTTP エンドポイントではなく、ドメインに対応付けます。

# Good — domain vocabulary
eden map show
eden changeset create --file data.json
eden changeset accept CS-45

# Bad — HTTP vocabulary
eden get /projects/123/map
eden post /changesets --body data.json
出力の仕様
  • デフォルト: 人間が読みやすい形式(テーブル、要約)
  • --json: 標準出力への機械可読な JSON
  • エラー: 標準エラー出力、終了コード 1、対処方法がわかるメッセージ
eden projects list              # Table: ID  NAME  CREATED
eden projects list --json       # [{"id":"...","name":"..."}]
eden changeset accept BAD-ID    # stderr: "Changeset BAD-ID not found"
自動検出パターン

リソースが 1 つしかない場合は、フラグを必須にせず自動検出します。

async function autoDetectProject(): Promise<string> {
  const projects = await api('GET', '/projects');
  if (projects.length === 1) return projects[0].id;
  if (projects.length === 0) {
    console.error('No projects found.');
    process.exit(1);
  }
  console.error('Multiple projects. Use --project <id>:');
  for (const p of projects) console.error(`  ${p.id}  ${p.name}`);
  process.exit(1);
}
段階的なヘルプ

すべてのコマンドとサブコマンドに --help を用意します。

$ eden --help
Eden story map CLI

Commands:
  projects    Manage projects
  map         View story map
  changeset   Create and review changesets
  persona     Manage personas
  question    Manage questions
  search      Search the map
  export      Export project data

$ eden changeset --help
Commands:
  create   Create a changeset from JSON file
  accept   Accept a pending changeset
  reject   Reject a pending changeset
  list     List changesets for a project

環境変数

CLI は以下の環境変数を読み取ります(Eve によって自動的に設定されます)。

変数用途設定元
EVE_APP_API_URL_{SERVICE}アプリ API のベース URLプラットフォーム(--with-apis)
EVE_JOB_TOKENBearer 認証トークンプラットフォーム(ジョブごと)
EVE_PROJECT_IDEve プラットフォームのプロジェクト IDプラットフォーム
EVE_ORG_IDEve プラットフォームの組織 IDプラットフォーム

CLI で手動設定が必要になることはありません。

ローカルでのテスト

環境変数を設定して、直接実行します。

export EVE_APP_API_URL_API=http://localhost:3000
export EVE_JOB_TOKEN=$(eve auth token)

# Test individual commands
./cli/bin/myapp projects list
./cli/bin/myapp items create --file test-data.json

バンドルの詳細

esbuild を使って、実行時依存関係のない単一ファイルを生成します。

  • --bundle はすべてのインポート(commander を含む)をインライン化します
  • --platform=node は Node.js の組み込み機能を対象にします
  • --target=node20 は Eve の実行環境に合わせます
  • --format=cjs は CommonJS を使用します(commander は内部で require() を使用します)
  • シバンは別途先頭に追加します(esbuild の --banner は #!/usr/bin/env 内の ! をエスケープします)
  • 結果:50〜200KB の単一ファイルで、実行時に node_modules は不要です

クローン後すぐに利用できるよう、cli/bin/myapp をリポジトリにコミットします。

イメージベースの配布(コンパイル済み CLI)

Go、Rust、その他のコンパイル型 CLI の場合:

services:
  api:
    x-eve:
      cli:
        name: myapp
        image: ghcr.io/org/myapp-cli:latest

CLI バイナリを /cli/bin/myapp に配置した Docker イメージをビルドします。

FROM rust:1.77 AS build
COPY . .
RUN cargo build --release

FROM busybox:stable
COPY --from=build /app/target/release/myapp /cli/bin/myapp

プラットフォームは init コンテナ経由で CLI を注入します(ツールチェーンと同じ方式で、レイテンシーは約 2〜5 秒です)。

関連項目

  • 完全な技術リファレンスについては、eve-read-eve-docs の references/app-cli.md を参照してください
  • マニフェストのスキーマの詳細については、references/manifest.md を参照してください
  • Eve Auth SDK(サーバー側のトークン検証)については、references/eve-sdk.md を参照してください

コメント