Skip to main content

create-plugin

Create a TIS plugin conforming to TIS plugin specifications

Informations de source

Dépôt
datavane/tis
Dernière activité de la source
26 octobre 2026 à 10:09
Langue détectée de SKILL.md
Plusieurs langues
Étoiles
1 439
Forks
304

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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. - **资源路径必须与源码包逐层对应**:`src/main/java/a/b/C.java` ↔ `src/main/resources/a/b/C.json`。放错一层目录(例如源码在 `a/b/event/C.java` 而 json 写成 `a/b/C.json`)**不会报错**,只是这个 json 永远不会被读到 —— 表单上 label/help/dftVal 全丢,且没有任何日志提示 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). The default counts only if it is `dftVal` in the `.json` — a Java field initializer does not pre-fill the form - **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; ``` #### 原则一之扩展:避免枚举 + 条件字段的耦合设计 **问题模式**:使用枚举字段控制其他字段的有效性,导致字段间产生关联性耦合。 **典型症状**: - 一个枚举字段(如 `source`)决定了其他字段(如 `parameterRef`、`literalValue`)是否有意义 - 这些条件字段在某些枚举值下被使用,在其他枚举值下被忽略 - 需要在 `validateAll()` 中写"如果枚举是 X,则字段 Y 必填"的逻辑 **错误示例**: ```java // ❌ 错误:枚举 + 条件字段耦合 public class PropertyMappingConfig { @FormField(ordinal = 1, type = FormFieldType.ENUM) public ValueSource source; // FROM_PARAMETER / CURRENT_TIME / LITERAL @FormField(ordinal = 2) public String parameterRef; // 仅 FROM_PARAMETER 时有效 @FormField(ordinal = 3) public String literalValue; // 仅 LITERAL 时有效 public enum ValueSource { FROM_PARAMETER, CURRENT_TIME, LITERAL } } ``` **正确做法**:将枚举改为抽象类 + 子类的多态设计,各子类持有各自的专属字段: ```java // ✅ 正确:抽象类 + 子类多态 public class PropertyMappingConfig { @FormField(ordinal = 1, validate = {Validator.require}) public ValueSourceConfig source; // 多态字段,TIS 自动检测为嵌套子表单 } // 抽象基类 public abstract class ValueSourceConfig implements Describable<ValueSourceConfig> { public abstract Object resolveValue(Map<String, Object> parameters); public static abstract class BaseDescriptor extends Descriptor<ValueSourceConfig> {} } // 子类一:从参数取值 public class FromParameterValueSource extends ValueSourceConfig { @FormField(ordinal = 0, type = FormFieldType.INPUTTEXT, validate = {Validator.require}) public String parameterRef; // 专属字段,只在这个子类中 @Override public Object resolveValue(Map<String, Object> parameters) {
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub