Token导航 LogoToken导航TokenDH.com
研究检索执行命令github未标认证来源可访问许可证需确认审计提醒

create-view创建视图

Agent Skill

create-view 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

424

周安装

17

GitHub Stars

19,422

下载量

137
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:create-view(创建视图)
来源仓库:https://github.com/wavetermdev/waveterm
仓库路径:skills/create-view
安装命令:
npx skills add https://github.com/wavetermdev/waveterm --skill create-view
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/wavetermdev/waveterm --skill create-view

简介

用于 Wave Terminal 新视图类型的开发与集成,支持模型与组件分离架构。

  • 提供 ViewModel 状态管理与 React 组件渲染的最佳实践指导。
  • 使用时需遵循 Jotai 原子化状态设计,确保视图可测试性与可维护性。
  • 建议先在沙箱环境中验证视图逻辑,再合并到主分支避免冲突。
  • create-view 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Creating a New View in Wave Terminal

This guide explains how to implement a new view type in Wave Terminal. Views are the core content components displayed within blocks in the terminal interface.

Architecture Overview

Wave Terminal uses a Model-View architecture where:

  • ViewModel - Contains all state, logic, and UI configuration as Jotai atoms
  • ViewComponent - Pure React component that renders the UI using the model
  • BlockFrame - Wraps views with a header, connection management, and standard controls

The separation between model and component ensures:

  • Models can update state without React hooks
  • Components remain pure and testable
  • State is centralized in Jotai atoms for easy access

ViewModel Interface

Every view must implement the ViewModel interface defined in frontend/types/custom.d.ts:

interface ViewModel {
  // Required: The type identifier for this view (e.g., "term", "web", "preview")
  viewType: string;

  // Required: The React component that renders this view
  viewComponent: ViewComponent<ViewModel>;

  // Optional: Icon shown in block header (FontAwesome icon name or IconButtonDecl)
  viewIcon?: jotai.Atom<string | IconButtonDecl>;

  // Optional: Display name shown in block header (e.g., "Terminal", "Web", "Preview")
  viewName?: jotai.Atom<string>;

  // Optional: Additional header elements (text, buttons, inputs) shown after the name
  viewText?: jotai.Atom<string | HeaderElem[]>;

  // Optional: Icon button shown before the view name in header
  preIconButton?: jotai.Atom<IconButtonDecl>;

  // Optional: Icon buttons shown at the end of the header (before settings/close)
  endIconButtons?: jotai.Atom<IconButtonDecl[]>;

  // Optional: Custom background styling for the block
  blockBg?: jotai.Atom<MetaType>;

  // Optional: If true, completely hides the block header
  noHeader?: jotai.Atom<boolean>;

  // Optional: If true, shows connection picker in header for remote connections
  manageConnection?: jotai.Atom<boolean>;

  // Optional: If true, filters out 'nowsh' connections from connection picker
  filterOutNowsh?: jotai.Atom<boolean>;

  // Optional: If true, removes default padding from content area
  noPadding?: jotai.Atom<boolean>;

  // Optional: Atoms for managing in-block search functionality
  searchAtoms?: SearchAtoms;

  // Optional: Returns whether this is a basic terminal (for multi-input feature)
  isBasicTerm?: (getFn: jotai.Getter) => boolean;

  // Optional: Returns context menu items for the settings dropdown
  getSettingsMenuItems?: () => ContextMenuItem[];

  // Optional: Focuses the view when called, returns true if successful
  giveFocus?: () => boolean;

  // Optional: Handles keyboard events, returns true if handled
  keyDownHandler?: (e: WaveKeyboardEvent) => boolean;

  // Optional: Cleanup when block is closed
  dispose?: () => void;
}

Key Concepts

Atoms: All UI-related properties must be Jotai atoms. This enables:

  • Reactive updates when state changes
  • Access from anywhere via globalStore.get()/globalStore.set()
  • Derived atoms that compute values from other atoms

ViewComponent: The React component receives these props:

type ViewComponentProps<T extends ViewModel> = {
  blockId: string; // Unique ID for this block
  blockRef: React.RefObject<HTMLDivElement>; // Ref to block container
  contentRef: React.RefObject<HTMLDivElement>; // Ref to content area
  model: T; // Your ViewModel instance
};

Step-by-Step Guide

1. Create the View Model Class

Create a new file for your view model (e.g., frontend/app/view/myview/myview-model.ts):

import { BlockNodeModel } from "@/app/block/blocktypes";
import { WOS, globalStore, useBlockAtom } from "@/store/global";
import * as jotai from "jotai";
import { MyView } from "./myview";

export class MyViewModel implements ViewModel {
  viewType: string;
  blockId: string;
  nodeModel: BlockNodeModel;
  blockAtom: jotai.Atom<Block>;

  // Define your atoms (simple field initializers)
  viewIcon = jotai.atom<string>("circle");
  viewName = jotai.atom<string>("My View");
  noPadding = jotai.atom<boolean>(true);

  // Derived atom (created in constructor)
  viewText!: jotai.Atom<HeaderElem[]>;

  constructor(blockId: string, nodeModel: BlockNodeModel) {
    this.viewType = "myview";
    this.blockId = blockId;
    this.nodeModel = nodeModel;
    this.blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);

    // Create derived atoms that depend on block data or other atoms
    this.viewText = jotai.atom((get) => {
      const blockData = get(this.blockAtom);
      const rtn: HeaderElem[] = [];

      // Add header buttons/text based on state
      rtn.push({
        elemtype: "iconbutton",
        icon: "refresh",
        title: "Refresh",
        click: () => this.refresh(),
      });

      return rtn;
    });
  }

  get viewComponent(): ViewComponent {
    return MyView;
  }

  refresh() {
    // Update state using globalStore
    // Never use React hooks in model methods
    console.log("refreshing...");
  }

  giveFocus(): boolean {
    // Focus your view component
    return true;
  }

  dispose() {
    // Cleanup resources (unsubscribe from events, etc.)
  }
}

2. Create the View Component

Create your React component (e.g., frontend/app/view/myview/myview.tsx):

import { ViewComponentProps } from "@/app/block/blocktypes";
import { MyViewModel } from "./myview-model";
import { useAtomValue } from "jotai";
import "./myview.scss";

export const MyView: React.FC<ViewComponentProps<MyViewModel>> = ({
    blockId,
    model,
    contentRef
}) => {
    // Use atoms from the model (these are React hooks - call at top level!)
    const blockData = useAtomValue(model.blockAtom);

    return (
        <div className="myview-container" ref={contentRef}>
            <div>Block ID: {blockId}</div>
            <div>View: {model.viewType}</div>
            {/* Your view content here */}
        </div>
    );
};

3. Register the View

Add your view to the BlockRegistry in frontend/app/block/block.tsx:

const BlockRegistry: Map<string, ViewModelClass> = new Map();
BlockRegistry.set("term", TermViewModel);
BlockRegistry.set("preview", PreviewModel);
BlockRegistry.set("web", WebViewModel);
// ... existing registrations ...
BlockRegistry.set("myview", MyViewModel); // Add your view here

The registry key (e.g., "myview") becomes the view type used in block metadata.

4. Create Blocks with Your View

Users can create blocks with your view type:

  • Via CLI: wsh view myview
  • Via RPC: Use the block's meta.view field set to "myview"

Real-World Examples

Example 1: Terminal View (term-model.ts)

The terminal view demonstrates:

  • Connection management via manageConnection atom
  • Dynamic header buttons showing shell status (play/restart)
  • Mode switching between terminal and vdom views
  • Custom keyboard handling for terminal-specific shortcuts
  • Focus management to focus the xterm.js instance
  • Shell integration status showing AI capability indicators

Key features:

this.manageConnection = jotai.atom((get) => {
  const termMode = get(this.termMode);
  if (termMode == "vdom") return false;
  return true; // Show connection picker for regular terminal mode
});

this.endIconButtons = jotai.atom((get) => {
  const shellProcStatus = get(this.shellProcStatus);
  const buttons: IconButtonDecl[] = [];

  if (shellProcStatus == "running") {
    buttons.push({
      elemtype: "iconbutton",
      icon: "refresh",
      title: "Restart Shell",
      click: this.forceRestartController.bind(this),
    });
  }
  return buttons;
});

Example 2: Web View (webview.tsx)

The web view shows:

  • Complex header controls (back/forward/home/URL input)
  • State management for loading, URL, and navigation
  • Event handling for webview navigation events
  • Custom styling with noPadding for full-bleed content
  • Media controls showing play/pause/mute when media is active

Key features:

this.viewText = jotai.atom((get) => {
  const url = get(this.url);
  const rtn: HeaderElem[] = [];

  // Navigation buttons
  rtn.push({
    elemtype: "iconbutton",
    icon: "chevron-left",
    click: this.handleBack.bind(this),
    disabled: this.shouldDisableBackButton(),
  });

  // URL input with nested controls
  rtn.push({
    elemtype: "div",
    className: "block-frame-div-url",
    children: [
      {
        elemtype: "input",
        value: url,
        onChange: this.handleUrlChange.bind(this),
        onKeyDown: this.handleKeyDown.bind(this),
      },
      {
        elemtype: "iconbutton",
        icon: "rotate-right",
        click: this.handleRefresh.bind(this),
      },
    ],
  });

  return rtn;
});

Header Elements (HeaderElem)

The viewText atom can return an array of these element types:

// Icon button
{
    elemtype: "iconbutton",
    icon: "refresh",
    title: "Tooltip text",
    click: () => { /* handler */ },
    disabled?: boolean,
    iconColor?: string,
    iconSpin?: boolean,
    noAction?: boolean,  // Shows icon but no click action
}

// Text element
{
    elemtype: "text",
    text: "Display text",
    className?: string,
    noGrow?: boolean,
    ref?: React.RefObject<HTMLElement>,
    onClick?: (e: React.MouseEvent) => void,
}

// Text button
{
    elemtype: "textbutton",
    text: "Button text",
    className?: string,
    title: "Tooltip",
    onClick: (e: React.MouseEvent) => void,
}

// Input field
{
    elemtype: "input",
    value: string,
    className?: string,
    onChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
    onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void,
    onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void,
    onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void,
    ref?: React.RefObject<HTMLInputElement>,
}

// Container with children
{
    elemtype: "div",
    className?: string,
    children: HeaderElem[],
    onMouseOver?: (e: React.MouseEvent) => void,
    onMouseOut?: (e: React.MouseEvent) => void,
}

// Menu button (dropdown)
{
    elemtype: "menubutton",
    // ... MenuButtonProps ...
}

Best Practices

Jotai Model Pattern

Follow these rules for Jotai atoms in models:

  1. Simple atoms as field initializers: viewIcon = jotai.atom<string>("circle"); noPadding = jotai.atom<boolean>(true);
  2. Derived atoms in constructor (need dependency on other atoms): constructor(blockId: string, nodeModel: BlockNodeModel) {this.viewText = jotai.atom((get) => {const blockData = get(this.blockAtom); return [/* computed based on blockData */];});}
  3. Models never use React hooks - Use globalStore.get()/set(): refresh() {const currentData = globalStore.get(this.blockAtom); globalStore.set(this.dataAtom, newData);}
  4. Components use hooks for atoms: const data = useAtomValue(model.dataAtom); const [value, setValue] = useAtom(model.valueAtom);

State Management

  • All view state should live in atoms on the model
  • Use useBlockAtom() helper for block-scoped atoms that persist
  • Use globalStore for imperative access outside React components
  • Subscribe to Wave events using waveEventSubscribe()

Styling

  • Create a .scss file for your view styles
  • Use Tailwind utilities where possible (v4)
  • Add noPadding: atom(true) for full-bleed content
  • Use blockBg atom to customize block background

Focus Management

Implement giveFocus() to focus your view when:

  • Block gains focus via keyboard navigation
  • User clicks the block
  • Return true if successfully focused, false otherwise

Keyboard Handling

Implement keyDownHandler(e: WaveKeyboardEvent) for:

  • View-specific keyboard shortcuts
  • Return true if event was handled (prevents propagation)
  • Use keyutil.checkKeyPressed(waveEvent, "Cmd:K") for shortcut checks

Cleanup

Implement dispose() to:

  • Unsubscribe from Wave events
  • Unregister routes/handlers
  • Clear timers/intervals
  • Release resources

Connection Management

For views that need remote connections:

this.manageConnection = jotai.atom(true); // Show connection picker
this.filterOutNowsh = jotai.atom(true); // Hide nowsh connections

Access connection status:

const connStatus = jotai.atom((get) => {
  const blockData = get(this.blockAtom);
  const connName = blockData?.meta?.connection;
  return get(getConnStatusAtom(connName));
});

Common Patterns

Reading Block Metadata

import { getBlockMetaKeyAtom } from "@/store/global";

// In constructor:
this.someFlag = getBlockMetaKeyAtom(blockId, "myview:flag");

// In component:
const flag = useAtomValue(model.someFlag);

Configuration Overrides

Wave has a hierarchical config system (global → connection → block):

import { getOverrideConfigAtom } from "@/store/global";

this.settingAtom = jotai.atom((get) => {
  // Checks block meta, then connection config, then global settings
  return get(getOverrideConfigAtom(this.blockId, "myview:setting")) ?? defaultValue;
});

Updating Block Metadata

import { RpcApi } from "@/app/store/wshclientapi";
import { TabRpcClient } from "@/app/store/wshrpcutil";
import { WOS } from "@/store/global";

await RpcApi.SetMetaCommand(TabRpcClient, {
  oref: WOS.makeORef("block", this.blockId),
  meta: { "myview:key": value },
});

Additional Resources

  • frontend/app/block/blockframe-header.tsx - Block header rendering
  • frontend/app/view/term/term-model.ts - Complex view example
  • frontend/app/view/webview/webview.tsx - Navigation UI example
  • frontend/types/custom.d.ts - Type definitions

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.78%
按下载量换算49

Claude

27.06%
按下载量换算37

Cursor

19.09%
按下载量换算26

Gemini CLI

9.74%
按下载量换算13

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

执行命令

安装流程涉及命令执行,可能通过 npx skills add https://github.com/wavetermdev/waveterm --skill create-view 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills