- name
- create-multi-steps-plugin
- description
- Create a TIS multi-steps plugin with dependent properties configured through multiple steps
# TIS Multi-Steps Plugin Creator
This skill helps you create a well-structured TIS multi-steps plugin that conforms to TIS multi-steps plugin specifications. Multi-steps plugins are used when plugin properties have logical dependencies (e.g., selecting a province before showing cities in that province).
## What This Skill Does
When invoked, this skill will:
1. Analyze the user-provided context to understand the plugin's multi-step functionality
2. Design the multi-steps plugin structure with host plugin and step plugins
3. Generate the complete implementation including:
- **Host Plugin Class**: Implements `MultiStepsSupportHost` and `IPluginStore.ManipuldateProcessor`
- **Host Descriptor**: Implements `MultiStepsSupportHostDescriptor` with step definitions
- **Step Plugin Classes**: Each step extends `OneStepOfMultiSteps`
- **Step Descriptors**: Extend `OneStepOfMultiSteps.BasicDesc` with navigation logic
- **Property descriptor files** (`.json`) for all plugins
- **Optional help documentation** (`.md`) for complex properties
## When to Use This Skill
Use this skill when:
1. User explicitly requests to invoke this skill
2. During assisted programming, you discover properties with semantic dependencies (like province → city), **and the user confirms** the need for a multi-steps plugin
## Reference Example
The primary reference example is:
- **Host Plugin**: `/Users/mozhenghua/j2ee_solution/project/plugins/tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/impl/valuetype/DefaultOntologyValueType.java`
- **Parent Class**: `tis-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/OntologyValueType.java`
- **Step 1**: `/Users/mozhenghua/j2ee_solution/project/plugins/tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/impl/valuetype/MetadataOfValueType.java`
- **Step 2**: `/Users/mozhenghua/j2ee_solution/project/plugins/tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/impl/valuetype/ConstraintsOfValueType.java`
## TIS Multi-Steps Plugin Specifications
### Core Requirements for Host Plugin
#### 1. Implement MultiStepsSupportHost Interface
The plugin class (or its parent) MUST implement `com.qlangtech.tis.extension.MultiStepsSupportHost` interface.
**Reference**: `tis-plugin/src/main/java/com/qlangtech/tis/extension/MultiStepsSupportHost.java`
Example (parent class):
```java
public abstract class OntologyValueType extends Ontology
implements IdentityName, MultiStepsSupportHost, IPluginStore.ManipuldateProcessor {
// ...
}
```
#### 2. Define stepsPlugin Property
The plugin class (or its parent) MUST have a `protected OneStepOfMultiSteps[] stepsPlugin` property and implement two methods from `MultiStepsSupportHost`:
```java
protected OneStepOfMultiSteps[] stepsPlugin;
@Override
public void setSteps(OneStepOfMultiSteps[] stepsPlugin) {
this.stepsPlugin = Objects.requireNonNull(stepsPlugin, "stepsPlugin can not be null");
final int FIXED_VALUE_TYPE_STEPS_LENGTH = 2; // Number of steps
if (stepsPlugin.length != FIXED_VALUE_TYPE_STEPS_LENGTH) {
throw new IllegalStateException("stepsPlugin.length must be equal to " + FIXED_VALUE_TYPE_STEPS_LENGTH);
}
}
// IMPORTANT: Must add @JSONField(serialize = false) annotation
@JSONField(serialize = false)
@Override
public OneStepOfMultiSteps[] getMultiStepsSavedItems() {
return stepsPlugin;
}
```
**Important Notes**:
- `setSteps()` should validate the array length matches the expected number of steps
- `getMultiStepsSavedItems()` MUST be annotated with `@JSONField(serialize = false)` to prevent duplicate serialization
#### 3. Implement IPluginStore.ManipuldateProcessor
The plugin class (or its parent) MUST implement `com.qlangtech.tis.plugin.IPluginStore.ManipuldateProcessor` interface to handle persistence logic.
**Reference**: See `tis-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/OntologyValueType.java:L152`
```java
@Override
public void manipuldateProcess(IPluginContext currentCtx) {
// Custom persistence logic
// Example: Save to custom storage, validate cross-step data, etc.
}
```
#### 4. Host Descriptor Requirements
The inner `@TISExtension` Descriptor class MUST implement `com.qlangtech.tis.extension.MultiStepsSupportHostDescriptor` interface.
**Reference**: `tis-plugin/src/main/java/com/qlangtech/tis/extension/MultiStepsSupportHostDescriptor.java`
Must implement two methods:
```java
@TISExtension
public static class DefaultDesc extends Ontology.BasicDesc
implements MultiStepsSupportHostDescriptor<OntologyValueType> {
@Override
public Class<OntologyValueType> getHostClass() {
return OntologyValueType.class;
}
@Override
public List<OneStepOfMultiSteps.BasicDesc> getStepDescriptionList() {
// Return step descriptors IN ORDER
return List.of(new MetadataOfValueType.Desc(), new ConstraintsOfValueType.Desc());
}
}
```
**Important Notes**:
- `getStepDescriptionList()` returns step descriptor instances **in execution order**
- The order in the list defines the step sequence (first element = Step 1, second = Step 2, etc.)
### Core Requirements for Step Plugins
#### 1. Extend OneStepOfMultiSteps
Each step plugin MUST extend `com.qlangtech.tis.extension.OneStepOfMultiSteps`.
**Reference**: `tis-plugin/src/main/java/com/qlangtech/tis/extension/OneStepOfMultiSteps.java`
```java
public class MetadataOfValueType extends OneStepOfMultiSteps
implements OntologyValueType.IMetadataOfValueType {
@FormField(ordinal = 0, validate = {Validator.require})
public String name;
// Other properties...
}
```
#### 2. Optional: Override processPreSaved()
Step plugins can override `processPreSaved()` to execute business logic when the user submits the step:
```java
@Override
public void processPreSaved(IPluginContext pluginContext) {
// Custom validation or processing logic
super.processPreSaved(pluginContext);
}
```
#### 3. Step Descriptor Requirements
The inner `@TISExtension` Descriptor MUST extend `OneStepOfMultiSteps.BasicDesc` and implement key methods:
```java
@TISExtension
public static class Desc extends OneStepOfMultiSteps.BasicDesc {
@Override
public String getStepDescription() {
return "Metadata"; // Step display name
}
@Override
public Step getStep() {
return Step.Step1; // Which step this is (Step1, Step2, etc.)
}
@Override
public Optional<BasicDesc> nextPluginDesc(OneStepOfMultiSteps current) {
// Return the next step's descriptor
return Optional.of(new ConstraintsOfValueType.Desc());
// For final step: return Optional.empty();
}
@Override
public boolean isFinalStep() {
return false; // true for the last step
}
}
```
**Important Notes**:
- `getStep()` must return the correct `Step` enum value (Step1, Step2, ..., Step7)
- `nextPluginDesc()` returns the next step's descriptor instance, or `Optional.empty()` for the final step
- `isFinalStep()` returns `true` only for the last step in the sequence
#### 4. Step Plugin Properties
Step plugins follow the same property rules as regular TIS plugins:
- All properties must be `public`
- Annotated with `@FormField`
- Have corresponding `.json` descriptor files
- Can use all standard validators and field types
- **See `/create-plugin` skill for detailed property specifications**
### Additional Specifications
#### 5. Override getDescriptor() with @JSONField
If the host plugin class overrides the parent's `getDescriptor()` method, it MUST add `@JSONField(serialize = false)` annotation:
**Reference**: See `tis-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/OntologyObjectType.java`
```java
@JSONField(serialize = false)
@Override
public Descriptor<Ontology> getDescriptor() {
return super.getDescriptor();
}
```
#### 6. Identity Support (Optional)
If the multi-steps plugin needs to be "identifiable" (parent class doesn't already implement `IdentityName`):
**Ask the user** whether the plugin should be identifiable. If yes:
1. Implement `com.qlangtech.tis.plugin.IdentityName` interface
2. Implement `identityValue()` method
3. Add a dummy identity field (TIS requirement):
```java
public abstract class OntologyValueType extends Ontology
implements IdentityName, MultiStepsSupportHost {
/**
* Caution: This field is currently unused but required since we implement IdentityName
*/
@FormField(identity = true, ordinal = 0, validate = {Validator.require, Validator.identity})
public String useless;
@Override
public String identityValue() {
// Usually return identity from first step
for (OneStepOfMultiSteps step : getMultiStepsSavedItems()) {
if (step instanceof IMetadataOfValueType meta) {
return meta.getName();
}
}
throw new IllegalStateException("illegal name have not been set");
}
}
```
## Instructions for Claude
When the user invokes `/create-multi-steps-plugin`, follow this workflow:
### Step 1: Analyze Context
- Ask the user to provide context about the multi-steps plugin they want to create (or the user may provide it directly)
- Analyze the context to determine:
- Plugin's purpose and multi-step workflow
- Number of steps required (2-7 steps)
- Properties for each step
- **Dependency relationships** between steps (how earlier steps influence later steps)
- Parent class to extend (if any)
- Whether the plugin needs to be identifiable
### Step 2: Design Multi-Steps Plugin Structure
Determine the plugin organization:
**Host Plugin**:
- Class name and package
- Parent class (if extending an existing plugin class)
- Whether it implements `IdentityName` (ask user if parent doesn't)
- Number of steps
- Any host-level methods or logic
**For Each Step** (Step 1, Step 2, ..., Step N):
- Step class name and package
- Step description (display name)
- Properties with types, FormFieldType, and validators
- Business logic in `processPreSaved()` if needed
- **How this step's properties depend on previous steps**
- Whether this is the final step
**Property Descriptor Files**:
- Which properties need `.json` descriptors
- Which properties need `.md` help files
### Step 3: Confirm Design with User
Before implementation, present:
1. **Host Plugin**:
- Class name, parent class, interfaces
- Number of steps
- Identity support (yes/no)
- Persistence logic requirements
2. **Step Details** (for each step):
- Step number and class name
- Step description
- Properties list with types and validators
- Dependency on previous steps
- Business logic requirements
3. **Files to Generate**:
- Host plugin: Java + JSON + optional MD
- Step 1 plugin: Java + JSON + optional MD
- Step 2 plugin: Java + JSON + optional MD
- ... (for each step)
Wait for user approval before proceeding.
### Step 4: Implement Multi-Steps Plugin
Generate files in the correct structure:
#### A. Host Plugin Java Class
**File structure**:
```
{package_path}/{HostPluginName}.java
```
**Must include**:
1. Package and imports
2. Class declaration implementing required interfaces:
- Extends parent class (if any)
- Implements `MultiStepsSupportHost` (or parent does)
- Implements `IPluginStore.ManipuldateProcessor` (or parent does)
- Optionally implements `IdentityName`
3. Properties:
- `protected OneStepOfMultiSteps[] stepsPlugin;` (if not in parent)
- Identity field if implementing `IdentityName`
4. Methods:
- `setSteps()` with validation
- `getMultiStepsSavedItems()` with `@JSONField(serialize = false)`
- `manipuldateProcess()` for persistence logic
- `identityValue()` if implementing `IdentityName`
- Getter methods for accessing specific steps (optional but recommended)
5. Inner Descriptor class:
- Annotated with `@TISExtension`
- Implements `MultiStepsSupportHostDescriptor<HostPluginClass>`
- Implements `getHostClass()` returning the host class
- Implements `getStepDescriptionList()` returning step descriptors in order
- Overrides `getDisplayName()`
**Example structure**:
```java
package com.qlangtech.tis.plugin.example;
import com.qlangtech.tis.extension.*;
import com.qlangtech.tis.plugin.IPluginStore;
// ... other imports
public class ExampleMultiStepsPlugin extends ParentClass
implements MultiStepsSupportHost, IPluginStore.ManipuldateProcessor {
protected OneStepOfMultiSteps[] stepsPlugin;
@Override
public void setSteps(OneStepOfMultiSteps[] stepsPlugin) {
this.stepsPlugin = Objects.requireNonNull(stepsPlugin);
if (stepsPlugin.length != 2) {
throw new IllegalStateException("Expected 2 steps");
}
}
@JSONField(serialize = false)
@Override
public OneStepOfMultiSteps[] getMultiStepsSavedItems() {
return stepsPlugin;
}
@Override
public void manipuldateProcess(IPluginContext currentCtx) {
// Custom persistence logic
}
// Optional: Typed getters for steps
public Step1Plugin getStep1() {
return (Step1Plugin) stepsPlugin[Step.Step1.getStepIndex()];
}
@TISExtension
public static class DefaultDesc extends ParentDesc
implements MultiStepsSupportHostDescriptor<ExampleMultiStepsPlugin> {
@Override
public Class<ExampleMultiStepsPlugin> getHostClass() {
return ExampleMultiStepsPlugin.class;
}
@Override
public List<OneStepOfMultiSteps.BasicDesc> getStepDescriptionList() {
return List.of(new Step1Plugin.Desc(), new Step2Plugin.Desc());
}
@Override
public String getDisplayName() {
return "Example Multi-Steps Plugin";
}
}
}
```
#### B. Host Plugin Property Descriptors
**File**: `src/main/resources/{package_path}/{HostPluginName}.json`
Follow the same JSON format rules as regular TIS plugins (see `/create-plugin` skill).
**Only include properties directly defined in the host plugin** (not properties from step plugins).
If the host plugin only has the `stepsPlugin` array and identity field, the JSON might be minimal or focus on those fields.
#### C. Step Plugin Java Classes (for each step)
**File structure**:
```
{package_path}/{StepPluginName}.java
```
**Must include**:
1. Package and imports
2. Class declaration:
- Extends `OneStepOfMultiSteps`
- Optionally implements interfaces for type safety
3. Public properties with `@FormField` annotations
4. Business methods (if needed)
5. Optional: Override `processPreSaved()` for step-specific logic
6. Inner Descriptor class:
- Annotated with `@TISExtension`
- Extends `OneStepOfMultiSteps.BasicDesc`
- Implements required methods:
- `getStepDescription()` - step display name
- `getStep()` - returns Step enum (Step1, Step2, etc.)
- `nextPluginDesc()` - returns next step or Optional.empty()
- `isFinalStep()` - true for last step
- Validation methods for properties
**Example structure**:
```java
package com.qlangtech.tis.plugin.example;
import com.qlangtech.tis.extension.*;
import com.qlangtech.tis.plugin.annotation.*;
// ... other imports
public class Step1Plugin extends OneStepOfMultiSteps {
@FormField(ordinal = 0, validate = {Validator.require})
public String name;
@FormField(ordinal = 1, type = FormFieldType.ENUM, validate = {Validator.require})
public int type;
@Override
public void processPreSaved(IPluginContext pluginContext) {
// Save this step's data to context for next step
Auf GitHub ansehen