Skip to main content

create-plugin

Create a TIS plugin conforming to TIS plugin specifications

ソース情報

リポジトリ
datavane/tis
ソースの最終更新活動
2026年10月4日 14:43
検出された SKILL.md の言語
複数言語
スター
1,425
フォーク
302

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
create-plugin
description
Create a TIS plugin conforming to TIS plugin specifications
# TIS Plugin Creator This skill helps you create a well-structured TIS (Data Integration Service) plugin that conforms to all TIS plugin specifications. ## Core Concepts ### 顶级插件 (Top-Level Plugin) 顶级插件是独立的主体,有独立的概念意义(可类比为一辆功能正常的车)。 **特征**: - 不被任何其他插件所聚合 - 直接或间接实现 `com.qlangtech.tis.extension.Describable` 接口 - **必须实现 `com.qlangtech.tis.plugin.IdentityName` 接口** (`tis-builder-api/.../plugin/IdentityName.java`) - 例如:`DeepSeekProvider` (LLM 提供者)、`DataxIcebergWriter` (数据写入器) ### 聚合属性插件 (Aggregated Property Plugin) 聚合属性插件单独存在没有意义,必须聚合在其他插件中才有意义(可类比为车上的轮胎)。 **特征**: - 作为其他插件的 `@FormField` 属性类型存在 - 直接或间接实现 `com.qlangtech.tis.extension.Describable` 接口 - 内部有 `@TISExtension` 标注的 Descriptor 类 - **不实现 `IdentityName` 接口** - Descriptor 通常继承父类的 `BasicDescriptor` - 例如:`TemperatureSampling` (作为 `LLMProvider.sampling` 属性)、`HadoopCatalog` (作为 `DataxIcebergWriter.catalog` 属性) **代码对比**: ```java // 顶级插件示例 public class DeepSeekProvider extends LLMProvider implements IdentityName { @FormField(ordinal = 0, identity = true) public String name; // IdentityName 要求的标识字段 @TISExtension public static class DftDesc extends Descriptor<DeepSeekProvider> { // 可以覆盖 httpProcess() (如果前端有需求) } } // LLMProvider 父类(展示聚合属性插件如何被使用) public abstract class LLMProvider implements Describable<LLMProvider>, IdentityName { // ↓ 这是聚合属性字段 —— Sampling 类型是 Describable,有多个子类型实现 @FormField(ordinal = 128, validate = {Validator.require}) public Sampling sampling; // 前端可以选择 TemperatureSampling / TopPSampling / TopKSampling 等 } // 聚合属性插件示例 public class TemperatureSampling extends Sampling { // 注意:未实现 IdentityName 接口 @FormField(ordinal = 0, validate = {Validator.require}) public Double temperature; // 温度参数 @TISExtension public static class DefaultDescriptor extends BasicDescriptor { // BasicDescriptor 定义在父类 Sampling 中 // 不要覆盖 httpProcess() —— 聚合属性插件不暴露独立 HTTP 端点 @Override public String shortComment() { return "温度采样策略"; } } } ``` **关系说明**: - `DeepSeekProvider` 是顶级插件,实现 `IdentityName`,用户创建实例时命名 - `LLMProvider.sampling` 字段类型为 `Sampling`(抽象基类) - `TemperatureSampling` 是 `Sampling` 的一个具体实现,作为聚合属性插件嵌入在 `LLMProvider` 中 - 前端展示 `DeepSeekProvider` 表单时,`sampling` 字段会渲染为下拉选择器,用户可选 `TemperatureSampling` / `TopPSampling` 等子类型 ## What This Skill Does When invoked, this skill will: 1. Analyze the user-provided context to understand the plugin's functionality 2. Design the plugin structure with appropriate properties (general or aggregated) 3. Generate the complete plugin implementation including: - Main plugin class implementing `Describable` - Inner `Descriptor` class with `@TISExtension` - Properties with proper `@FormField` annotations - Property validation methods - Corresponding `.json` property descriptor file - Optional `.md` help documentation ## TIS Plugin Specifications ### Core Requirements Every TIS plugin MUST satisfy: 1. **Implement Describable Interface** - Plugin class must implement `com.qlangtech.tis.extension.Describable` (directly or via parent) 2. **Inner Descriptor Class** - Must have a `public` inner class extending `com.qlangtech.tis.extension.Descriptor` - Annotated with `@TISExtension` from `com.qlangtech.tis.extension.TISExtension` 3. **Property Requirements** - All properties must be `public` - Must be annotated with `@FormField` 4. **Property Descriptor Files** - A `.json` file in the same package under `resources/` directory - Optional `.md` file for rich markdown help content - **IMPORTANT: parent classes also need `.json`!** Even if a class is `abstract` and has no `@TISExtension` Descriptor of its own, if it declares `@FormField` fields (public fields with `@FormField` annotation), it MUST have its own `.json` file at the matching resource path. These fields' help/placeholder/dftVal are inherited by concrete subclasses; TIS looks up the `.json` for each class in the hierarchy independently. 5. **Descriptor 命名:`getDisplayName()` 禁止返回中文(CRITICAL)** - `Descriptor#getDisplayName()` 是插件的机器可读短名,**必须由纯字母组成**:不得包含中文、空格以及任何标点符号 - 需要表达中文功能说明时,让 Descriptor 实现 `com.qlangtech.tis.extension.DescriptorUseableShortComment` 接口 (`tis-plugin/src/main/java/com/qlangtech/tis/extension/DescriptorUseableShortComment.java`), 把原来的中文内容移到 `shortComment()` 的返回值,`getDisplayName()` 改写成对应的英文短名 - 命名规则:**下划线分隔的帕斯卡命名**(每个单词首字母大写,单词之间用 `_` 分隔); 全大写缩写保持全大写(`LLM` / `URL` / `AIP`);单个单词时无需下划线 - 示例对照: | 类名 | ✅ `getDisplayName()` | ✅ `shortComment()` | |---|---|---| | `CloseOverlayConfig.DefaultDescriptor` | `Close_Overlay` | `关闭浮层` | | `DisableAutoRefreshConfig.DefaultDescriptor` | `Disable_Auto_Refresh` | `关闭自动刷新` | | `StreamLlmConfig.DefaultDescriptor` | `Stream_LLM` | `调用大模型` | | `RecomputeConfig.DefaultDescriptor` | `Recompute` | `重算变量` | | `UrlClickAction.DefaultDescriptor` | `URL` | `跳转链接` | - ❌ 反例:`return "关闭浮层";`(中文)、`return "Close Overlay";`(含空格)、`return "closeOverlay";`(单词首字母未大写) - 本规则对**所有** Descriptor 子类生效,顶级插件 (Top-Level Plugin) 与聚合属性插件 (Aggregated Property Plugin) 一视同仁 ### Property Types #### General Properties Basic Java types: - `Boolean` / `boolean` - `Integer` / `int` - `String` - `Long` / `long` - `java.util.Date` - `com.qlangtech.tis.plugin.MemorySize` - Duration types #### Aggregated Properties Properties that are themselves `Describable` plugins, providing polymorphic capability. Example: `ClusterType` in `TISFlinkCDCStreamFactory`. **CRITICAL - @FormField for Aggregated Properties**: - **NEVER specify `type` attribute in @FormField for aggregated properties** - TIS automatically detects aggregated properties (properties implementing `Describable`) - Adding `type = FormFieldType.SELECTABLE` will cause TIS runtime errors **Correct** ✅: ```java @FormField(ordinal = 0, validate = {Validator.require}) public OntologyActionRule sideEffectRule; ``` **Wrong** ❌: ```java @FormField(ordinal = 0, type = FormFieldType.SELECTABLE, validate = {Validator.require}) public OntologyActionRule sideEffectRule; // This will fail at runtime! ``` **IMPORTANT**: Each concrete implementation class of a 聚合属性插件 (Aggregated Property Plugin) is a full plugin and MUST have: - Its own Java class with `@FormField` properties - Its own `@TISExtension` Descriptor - **Descriptor MUST implement `DescriptorUseableShortComment` interface** (from `tis-plugin/src/main/java/com/qlangtech/tis/extension/DescriptorUseableShortComment.java`) - Implement `shortComment()` method returning a **brief Chinese description** of the plugin's function - **Requirements for shortComment()**: - Use Chinese language (中文) - **Maximum 10 characters** (10个字以内) - **NO punctuation marks** (no periods, commas, etc.) - Will be displayed in the frontend UI to help users understand the plugin at a glance - Example: "Hadoop文件系统管理" or "Hive元数据存储" - 🔴 **同一个 Descriptor 的 `getDisplayName()` 不得返回中文**:中文说明只出现在 `shortComment()`, `getDisplayName()` 必须返回纯字母的英文短名(如 `Hadoop_Catalog`)。详见 "Core Requirements" 第 5 条 - Its own `.json` descriptor file in resources (same package path) - Optional `.md` help file if properties are complex **IdentityName Interface Rule (CRITICAL)**: - **聚合属性插件 (Aggregated Property Plugin) implementation classes generally DO NOT need to implement `IdentityName` interface** - IdentityName is typically used for 顶级插件 (Top-Level Plugin), not nested 聚合属性插件 - Reference: `tis-builder-api/src/main/java/com/qlangtech/tis/plugin/IdentityName.java` - **If a plugin implements `IdentityName` interface, it MUST have an identity property**: - One `@FormField` property MUST be marked with `identity = true` - Example: `@FormField(ordinal = 0, identity = true, validate = {Validator.require, Validator.identity})` - Without this, TIS will fail to start with an error - The identity property acts as the unique identifier for the plugin instance - **When to implement IdentityName**: - 顶级插件 (Top-Level Plugin) that users create multiple instances of (data sources, writers, readers) - Plugins that need to be referenced by name across the system - NOT for 聚合属性插件 (Aggregated Property Plugin) embedded within other plugins **Parent Class Requirements for 聚合属性插件 (Aggregated Property Plugin)**: - If a 聚合属性插件 type (e.g., `IcebergCatalog`) will have multiple concrete implementations, the **parent abstract class MUST define a `BasicDescriptor`**: - Must be a **protected abstract static** inner class - Must extend `Descriptor<ParentClassName>` - All concrete implementation classes' Descriptors MUST extend this `BasicDescriptor` - Example structure in parent class: ```java public abstract class IcebergCatalog implements Describable<IcebergCatalog> { // properties... protected abstract static class BasicDescriptor extends Descriptor<IcebergCatalog> { // common descriptor logic for all implementations } } ``` - Example in implementation class: ```java public class HadoopCatalog extends IcebergCatalog { // properties... @TISExtension() public static class DefaultDescriptor extends BasicDescriptor implements DescriptorUseableShortComment { @Override public String shortComment() { return "基于HDFS文件系统"; } @Override public String getDisplayName() { // 纯字母英文短名,下划线分隔帕斯卡命名;中文一律放 shortComment() return "Hadoop_Catalog"; } } } ``` Example: If `DataxIcebergWriter` has a 聚合属性插件 (Aggregated Property Plugin) `IcebergCatalog catalog`, and `HadoopCatalog` extends `IcebergCatalog`, then you need: - `IcebergCatalog.java` (abstract parent with protected abstract static BasicDescriptor inner class) - `HadoopCatalog.java` (with its own @FormField properties, Descriptor extends BasicDescriptor) - `HadoopCatalog.json` (describing HadoopCatalog's own properties) - Descriptor implements `DescriptorUseableShortComment` with `shortComment()` returning Chinese text (≤10 chars, no punctuation) - Optional `HadoopCatalog.md` (if properties are complex) - **DO NOT implement IdentityName** unless this is a 顶级插件 (Top-Level Plugin) (it's not in this case) ### @FormField Annotation Attributes - **identity**: Unique identifier for the plugin instance (acts as primary key) - **ordinal**: Display order in UI form (lower = higher priority, semantically related fields should be adjacent) - **advance**: Mark as advanced setting (must have default value, can be hidden) - **validate**: Frontend validation rules (see Validator options below) - **type**: Field type (see FormFieldType options below) ### Validator Options Reference: `tis-plugin/src/main/java/com/qlangtech/tis/plugin/annotation/Validator.java` - `require`: Required field - `user_name`: Username format (letters, numbers, underscore, dot, dash) - `email`: Email format - `forbid_start_with_number`: Cannot start with number - `identity`: Primary key format - `integer`: Integer format - `host`: Internet domain with optional port (e.g., `192.168.28.200:7070`) - `hostWithoutPort`: Domain without port - `url`: URL starting with http/https - `db_col_name`: Database column name format - `relative_path`: File system relative path - `absolute_path`: Unix absolute path - `none_blank`: Non-empty content ### FormFieldType Options Reference: `tis-plugin/src/main/java/com/qlangtech/tis/plugin/annotation/FormFieldType.java` - `MULTI_SELECTABLE`: Multi-select, property type `List<IdentityName>` or `List<String>` - `INPUTTEXT`: Single-line text input, property type `String` - `SELECTABLE`: Single-select dropdown (register options via `registerSelectOptions()` in Descriptor) - `PASSWORD`: Password input - `FILE`: File upload (only one per form, plugin must implement `ITmpFileStore`) - `TEXTAREA`: Multi-line text input (for SQL scripts, XML, etc.) - `DATE`: Date picker - `JDBCColumn`: JDBC column type - `INT_NUMBER`: Integer number input - `ENUM`: Enumeration selection - `DateTime`: Date-time (UTC, property type `long` or `java.util.Date`) - `DECIMAL_NUMBER`: Decimal number - `DURATION_OF_SECOND`: Duration in seconds - `DURATION_OF_MINUTE`: Duration in minutes - `DURATION_OF_HOUR`: Duration in hours - `MEMORY_SIZE_OF_BYTE`: Memory size in bytes - `MEMORY_SIZE_OF_KIBI`: Memory size in KB - `MEMORY_SIZE_OF_MEGA`: Memory size in MB ### FormFieldType 选用原则 #### 原则一:禁止 JSON 字符串输入 结构化数据不得使用 `TEXTAREA` 让用户填写 JSON 字符串,必须使用 TIS 的结构化表单机制: | 场景 | 正确做法 | 错误做法 | |---|---|---| | 列表化结构对象(如表格列配置) | `@SubForm(desClazz = XxxConfig.class)` + `List<XxxConfig>` | `@FormField(type = FormFieldType.TEXTAREA)` 手写 `[{...}]` | | 单个结构对象 | 字段类型声明为 `Describable` 子类,不指定 type(TIS 自动检测) | `@FormField(type = FormFieldType.TEXTAREA)` 手写 `{...}` | ```java // ✅ 正确:使用 @SubForm @SubForm(desClazz = WidgetColumnConfig.class, atLeastOne = false, idListGetScript = "return java.util.Collections.emptyList();") public List<WidgetColumnConfig> columns; // ❌ 错误:让用户手写 JSON @FormField(type = FormFieldType.TEXTAREA) public String columns; ``` #### 原则二:固定取值用 ENUM,动态选项用 SELECTABLE - **`ENUM`**:字段的取值集合同定有限,在 Java 代码中用枚举类硬编码。如:聚合方式(sum/count/avg/min/max)、对齐方式(left/center/right)、级别(1/2/3/4)、颜色选择(20种常用颜色)。 - **`SELECTABLE`**:选项来自运行时外部数据源,通过 `registerSelectOptions()` 或 `doGetOptions()` 动态供给。如:当前 module 的变量列表、数据库表名列。 ```java // ✅ 正确:固定取值用 ENUM + Java 枚举类 @FormField(type = FormFieldType.ENUM, ordinal = 3, required = true) public AggregationType aggregation; public enum AggregationType { sum("求和"), count("计数"), avg("平均值"), min("最小值"), max("最大值"); public final String label; AggregationType(String label) { this.label = label; } } // ❌ 错误:固定取值用 SELECTABLE(误导为动态选项) @FormField(type = FormFieldType.SELECTABLE, ordinal = 3) public String aggregation; // ❌ 错误:固定取值用 INPUTTEXT(用户不知道合法值) @FormField(type = FormFieldType.INPUTTEXT, ordinal = 3) public String aggregation; ``` #### 原则三:颜色类枚举附带 hex 色值 枚举字段为颜色选择时,在 `.json` resource 中为每个枚举项附带 `hex` 色值,用以前端渲染颜色预览圆点: ```json { "color": { "help": "选择文本颜色", "dftVal": "inherit", "enum": [ { "label": "红色", "val": "red", "hex": "#f5222d" }, { "label": "蓝色", "val": "blue", "hex": "#1890ff" } ] } } ``` #### 原则四:SELECTABLE 字段必须在 Descriptor 中注册选项
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る