Communitygithub.com

Lev-it/lev-skills

JSONスペックをインタラクティブなターミナルUIに変換するInkターミナルレンダラー。@json-render/inkの操作、ターミナルUI構築、コンポーネントカタログ作成、AI生成スペックのターミナル表示に使用します。

lev-skills とは?

このスキルは、JSON仕様(スペック)をインタラクティブなターミナルコンポーネントツリーに変換するInkターミナルレンダラー「@json-render/ink」を提供します。開発者はフラットな要素マップ形式のJSONを記述するだけで、Box、Text、Table、Spinner、TextInput、Selectなどの標準コンポーネントを用いたリッチなターミナルUIを構築できます。このスキルの主な利点は、ターミナルアプリケーションの状態管理、可視性条件、動的プロパティ式、イベント駆動のアクションシステムをシームレスに統合している点で、特にAIエージェントが生成したUI仕様をそのままターミナル上でレンダリングする用途に最適です。TypeScriptで型安全にカスタムコンポーネントを追加・登録でき、複数のプロバイダ(状態、アクション、可視性等)が組み込まれているため、複雑なインタラクションも容易に実現できます。また、ストリーミングAPIにも対応しており、大規模言語モデルからの段階的なUI更新を瞬時に表示することが可能です。外部状態管理もサポートしており、既存のアプリケーションへの統合もスムーズに行えます。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Lev-it/lev-skills/tree/HEAD/.claude/skills/ink

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

@json-render/ink

JSONスペックをインタラクティブなターミナルコンポーネントツリーに変換するInkターミナルレンダラー。標準コンポーネント、データバインディング、可視性、アクション、動的プロパティをサポート。

クイックスタート

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/ink/schema";
import {
  standardComponentDefinitions,
  standardActionDefinitions,
} from "@json-render/ink/catalog";
import { defineRegistry, Renderer, type Components } from "@json-render/ink";
import { z } from "zod";

// 標準+カスタムコンポーネントでカタログを作成
const catalog = defineCatalog(schema, {
  components: {
    ...standardComponentDefinitions,
    CustomWidget: {
      props: z.object({ title: z.string() }),
      slots: [],
      description: "カスタムウィジェット",
    },
  },
  actions: standardActionDefinitions,
});

// カスタムコンポーネントのみ登録(標準コンポーネントは組み込み済み)
const { registry } = defineRegistry(catalog, {
  components: {
    CustomWidget: ({ props }) => <Text>{props.title}</Text>,
  } as Components<typeof catalog>,
});

// レンダリング
function App({ spec }) {
  return (
    <JSONUIProvider initialState={{}}>
      <Renderer spec={spec} registry={registry} />
    </JSONUIProvider>
  );
}

スペック構造(フラットな要素マップ)

Inkスキーマはルートキーを持つフラットな要素マップを使用します:

{
  "root": "main",
  "elements": {
    "main": {
      "type": "Box",
      "props": { "flexDirection": "column", "padding": 1 },
      "children": ["heading", "content"]
    },
    "heading": {
      "type": "Heading",
      "props": { "text": "Dashboard", "level": "h1" },
      "children": []
    },
    "content": {
      "type": "Text",
      "props": { "text": "Hello from the terminal!" },
      "children": []
    }
  }
}

標準コンポーネント

レイアウト

  • Box - Flexboxレイアウトコンテナ(ターミナル用 <div>)。グループ化、スペーシング、ボーダー、配置に使用。デフォルトのflexDirectionは row。
  • Text - オプションのスタイリング(color、bold、italic など)でテキストを出力
  • Newline - 空行を挿入。flexDirection が column の Box 内で使用する必要がある
  • Spacer - 主軸に沿って伸縮するフレキシブルな空スペース

コンテンツ

  • Heading - セクション見出し(h1: bold+underlined、h2: bold、h3: bold+dimmed、h4: dimmed)
  • Divider - オプションの中央タイトル付き水平区切り線
  • Badge - 色付きインラインラベル(バリアント: default、info、success、warning、error)
  • Spinner - オプションラベル付きアニメーション読み込みスピナー
  • ProgressBar - 水平プログレスバー(0~1)
  • Sparkline - Unicodeブロック文字を使用したインラインチャート
  • BarChart - ラベルと値付きの水平棒グラフ
  • Table - ヘッダーと行を持つ表形式データ
  • List - 箇条書きまたは番号付きリスト
  • ListItem - タイトル、サブタイトル、先頭/末尾テキストを含む構造化リスト行
  • Card - オプションタイトル付きボーダーコンテナ
  • KeyValue - キーと値のペア表示
  • Link - オプションラベル付きクリック可能なURL
  • StatusLine - 色付きアイコン付きステータスメッセージ(info、success、warning、error)
  • Markdown - ターミナルスタイルでマークダウンテキストをレンダリング

インタラクティブ

  • TextInput - テキスト入力フィールド(イベント: submit、change)
  • Select - 矢印キーナビゲーションでの選択メニュー(イベント: change)
  • MultiSelect - スペースキーでトグルする複数選択(イベント: change、submit)
  • ConfirmInput - Yes/No確認プロンプト(イベント: confirm、deny)
  • Tabs - 左右矢印キーで操作するタブバーナビゲーション(イベント: change)

可視性条件

要素に visible を使用して、状態に基づいて表示/非表示を切り替えます。構文: { "$state": "/path" }、{ "$state": "/path", "eq": value }、{ "$state": "/path", "not": true }、AND条件には { "$and": [cond1, cond2] }、OR条件には { "$or": [cond1, cond2] }。

動的プロパティ式

任意のプロパティ値は、レンダリング時に解決されるデータ駆動型の式にできます:

  • { "$state": "/state/key" } - 状態モデルから読み取る(一方向読み取り)
  • { "$bindState": "/path" } - 双方向バインディング。フォームコンポーネントの自然な値プロパティで使用
  • { "$bindItem": "field" } - リピートアイテムフィールドへの双方向バインディング
  • { "$cond": <条件>, "$then": <値>, "$else": <値> } - 条件付き値
  • { "$template": "Hello, ${/name}!" } - 状態値を文字列に補間

コンポーネントは双方向バインディングに statePath プロパティを使用しません。代わりに、自然な値プロパティに { "$bindState": "/path" } を使用します。

イベントシステム

コンポーネントは emit を使用して名前付きイベントを発行します。要素の on フィールドはイベントをアクションバインディングにマッピングします:

CustomButton: ({ props, emit }) => (
  <Box>
    <Text>{props.label}</Text>
    {/* emit("press") でスペックの on.press にバインドされたアクションをトリガー */}
  </Box>
),
{
  "type": "CustomButton",
  "props": { "label": "Submit" },
  "on": { "press": { "action": "submit" } },
  "children": []
}

組み込みアクション

setState、pushState、removeState は組み込みで自動処理されます:

{ "action": "setState", "params": { "statePath": "/activeTab", "value": "home" } }
{ "action": "pushState", "params": { "statePath": "/items", "value": { "text": "New" } } }
{ "action": "removeState", "params": { "statePath": "/items", "index": 0 } }

Repeat(動的リスト)

コンテナ要素に repeat フィールドを使用して、状態配列からアイテムをレンダリングします:

{
  "type": "Box",
  "props": { "flexDirection": "column" },
  "repeat": { "statePath": "/items", "key": "id" },
  "children": ["item-row"]
}

繰り返し子要素内では、{ "$item": "field" } で現在のアイテムを読み取り、{ "$index": true } で現在のインデックスを取得します。

ストリーミング

useUIStream を使用して、JSONLパッチストリームからスペックを段階的にレンダリングします:

import { useUIStream } from "@json-render/ink";

const { spec, send, isStreaming } = useUIStream({ api: "/api/generate" });

サーバーサイドプロンプト生成

./server エクスポートを使用して、カタログからAIシステムプロンプトを生成します:

import { catalog } from "./catalog";

const systemPrompt = catalog.prompt({ system: "You are a terminal assistant." });

プロバイダ

プロバイダ目的
StateProviderコンポーネント間で状態を共有(JSON Pointer パス)。制御モード用にオプションの store プロパティを受け入れます。
ActionProviderイベントシステムを介してディスパッチされたアクションを処理
VisibilityProvider状態に基づく条件付きレンダリングを有効化
ValidationProviderフォームフィールドのバリデーション
FocusProviderインタラクティブコンポーネント間のフォーカス管理
JSONUIProviderすべてのコンテキストを統合したプロバイダ

外部ストア(制御モード)

StateStore を StateProvider(または JSONUIProvider)に渡して外部状態管理を使用します:

import { createStateStore, type StateStore } from "@json-render/ink";

const store = createStateStore({ count: 0 });

<StateProvider store={store}>{children}</StateProvider>

store.set("/count", 1); // Reactが自動的に再レンダリング

store が指定された場合、initialState と onStateChange は無視されます。

createRenderer(高レベルAPI)

import { createRenderer } from "@json-render/ink";
import { standardComponents } from "@json-render/ink";
import { catalog } from "./catalog";

const InkRenderer = createRenderer(catalog, {
  ...standardComponents,
  // ここでカスタムコンポーネントを上書き
});

// InkRenderer はすべてのプロバイダを含む(状態、可視性、アクション、フォーカス)
render(
  <InkRenderer spec={spec} state={{ activeTab: "overview" }} />
);

主要エクスポート

エクスポート目的
defineRegistryカタログから型安全なコンポーネントレジストリを作成
Rendererレジストリを使用してスペックをレンダリング
createRenderer高レベル: 組み込みプロバイダ付きコンポーネントを作成
JSONUIProviderすべてのコンテキストを統合したプロバイダ
schemaInkフラット要素マップスキーマ(組み込み状態アクションを含む)
standardComponentDefinitionsすべての標準コンポーネントのカタログ定義
standardActionDefinitions標準アクションのカタログ定義
standardComponents事前構築済みコンポーネント実装
useStateStore状態コンテキストにアクセス
useStateValue状態から単一の値を取得
useBoundProp$bindState/$bindItem 式の双方向バインディング
useActionsアクションコンテキストにアクセス
useAction単一のアクションディスパッチ関数を取得
useOptionalValidationuseValidation の非スロー版
useUIStreamAPIエンドポイントからスペックをストリーミング
createStateStoreフレームワーク非依存のインメモリ StateStore を作成
StateStore外部状態管理をプラグインするためのインターフェース
Components型付きコンポーネントマップ(カタログ対応)
Actions型付きアクションマップ(カタログ対応)
ComponentContext型付きコンポーネントコンテキスト(カタログ対応)
flatToTreeフラットな要素マップをツリー構造に変換

ターミナルUIデザインガイドライン

  • レイアウトには Box を使用(flexDirection、padding、gap)。デフォルトのflexDirectionは row。
  • ターミナル幅は約80~120カラム。メイン構造には垂直レイアウト(flexDirection: column)を推奨。
  • Box で視覚的なグループ化に borderStyle を使用(single、double、round、bold)。
  • 名前付きターミナルカラーを使用: red、green、yellow、blue、magenta、cyan、white、gray。
  • セクションタイトルには Heading、セクション区切りには Divider、ステータス表示には Badge、ラベル付きデータには KeyValue、ボーダーグループには Card を使用。
  • マルチビューUIには、子コンテンツに可視条件を設定した Tabs を使用。
  • インライントレンドには Sparkline、値の比較には BarChart を使用。

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

Lev-it/lev-skills

Ask which skill or flow fits your situation. A router over the user-invoked skills in this repo.

Lev-it/lev-skills

Premium brand-kit image generation skill for creating high-end brand-guidelines boards, logo systems, identity decks, and visual-world presentations. Trained for minimalist, cinematic, editorial, dark-tech, luxury, cultural, security, gaming, developer-tool, and consumer-app brand systems. Optimized for intentional logo concepting, refined composition, sparse typography, strong symbolic meaning, premium mockups, art-directed imagery, and flexible grid layouts.

Lev-it/lev-skills

Compact the current conversation into a handoff document for another agent to pick up.

Lev-it/lev-skills

Interactive QA session where user reports bugs or issues conversationally, and the agent files GitHub issues. Explores the codebase in the background for context and domain language. Use when user wants to report bugs, do QA, file issues conversationally, or mentions "QA session".

Lev-it/lev-skills

Facilitate a structured sprint retrospective — what went well, what didn't, and prioritized action items with owners and deadlines. Use when running a retrospective, reflecting on a sprint, creating action items from team feedback, or learning how to run effective retros.

Lev-it/lev-skills

Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/PRD asked for?). Runs both reviews in parallel sub-agents and reports them side by side. Use when the user wants to review a branch, a PR, work-in-progress changes, or asks to "review since X".

Lev-it/lev-skills

Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.

Lev-it/lev-skills

Teach the user a new skill or concept, within this workspace.

Lev-it/lev-skills

Turn the current conversation into a PRD and publish it to the project issue tracker — no interview, just synthesis of what you've already discussed.

Lev-it/lev-skills

Move issues through a state machine of triage roles — categorise, reproduce, grill if needed, and write agent-ready briefs.

Lev-it/lev-skills

Create product backlog items in Why-What-Acceptance format — independent, valuable, testable items with strategic context. Use when writing structured backlog items, breaking features into work items, or using the WWA format.

関連スキル