Communitygithub.com

Lev-it/lev-skills

基于 JSON 的 Ink 终端渲染器,将 JSON 规范转换为交互式终端 UI。适用于与 @json-render/ink 配合使用、从 JSON 构建终端 UI、创建终端组件目录或在终端中渲染 AI 生成的规范。

lev-skills 是什么?

`@json-render/ink` 是一个基于 React Ink 的终端渲染器,它能够将 JSON 规范(spec)实时渲染成交互式终端组件树。该工具支持大量标准 UI 组件,如布局容器 (Box)、文本、表格、图表、表单控件等,并提供了数据绑定、条件可见性、事件系统和内置动作(如状态修改)。它特别适用于 AI Agent 工具(如 Claude Code、Cursor)在终端中动态生成和展示 UI,或用于快速构建基于 JSON 的终端工具原型。该工具支持通过 `StateProvider` 进行状态管理,并提供了流式渲染 (`useUIStream`) 和服务端提示生成功能,使其成为构建动态、数据驱动的终端界面的强大引擎。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Lev-it/lev-skills/tree/HEAD/.claude/skills/ink

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

@json-render/ink

Ink 终端渲染器,可将 JSON 规范转换为交互式终端组件树,支持标准组件、数据绑定、可见性、动作和动态属性。

快速开始

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": "仪表盘", "level": "h1" },
      "children": []
    },
    "content": {
      "type": "Text",
      "props": { "text": "来自终端的问候!" },
      "children": []
    }
  }
}

标准组件

布局

  • Box - Flexbox 布局容器(类似终端的 <div>)。用于分组、间距、边框、对齐。默认 flexDirection 为 row。
  • Text - 文本输出,支持可选样式(颜色、粗体、斜体等)
  • Newline - 插入空行。必须位于 flexDirection 为 column 的 Box 内部。
  • Spacer - 沿主轴伸缩的弹性空白空间。

内容

  • Heading - 章节标题(h1:粗体+下划线,h2:粗体,h3:粗体+暗淡,h4:暗淡)
  • 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 - 渲染 markdown 文本,应用终端样式

交互式

  • TextInput - 文本输入字段(事件:submit, change)
  • Select - 支持箭头键导航的选择菜单(事件:change)
  • MultiSelect - 多选,按空格键切换(事件:change, submit)
  • ConfirmInput - 是/否确认提示(事件: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": "你好,${/name}!" } - 将状态值插值到字符串中

组件不应为双向绑定使用 statePath 属性。请改用自然值属性上的 { "$bindState": "/path" }。

事件系统

组件使用 emit 来触发命名事件。元素的 on 字段将事件映射到动作绑定:

CustomButton: ({ props, emit }) => (
  <Box>
    <Text>{props.label}</Text>
    {/* emit("press") 触发规范中 on.press 绑定的动作 */}
  </Box>
),
{
  "type": "CustomButton",
  "props": { "label": "提交" },
  "on": { "press": { "action": "submit" } },
  "children": []
}

内置动作

setState、pushState 和 removeState 是内置动作,会自动处理:

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

重复(动态列表)

在容器元素上使用 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: "你是一个终端助手。" });

提供者

提供者用途
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 的非抛出变体
useUIStream从 API 端点流式获取规范
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 表示带边框的分组。
  • 使用 Tabs 实现多视图 UI,并在子内容上使用可见性条件。
  • 使用 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.

相关技能