Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问clear审计未展示

eae-forkEAE 叉子

Agent Skill

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

总安装

751

周安装

31

GitHub Stars

公开资料未说明

下载量

246
CodexClaudeCursorGemini CLI

安装说明

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

GitHub

来源数

2

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

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

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

命令行安装

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

AgentSkills.tonpx skills
npx skills add sapiencezk/eae-skills --skill "eae-fork"

简介

eae-fork 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中快速定位候选结果。

  • 适用于分支管理、代码复用或并行任务处理场景,支持基于关键词的任务匹配。
  • 通过 npx skills add 命令从 GitHub 仓库安装,支持多宿主平台集成。
  • 安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • eae-fork 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

name
eae-fork
description
>
license
MIT
compatibility
Designed for EcoStruxure Automation Expert, Python 3.8+, PowerShell (Windows)
metadata
version
7.2.0
author
Claude
domain
industrial-automation
platform
EcoStruxure Automation Expert
parent-skill
eae-skill-router
user-invocable
true
standard
IEC-61499

EAE Block Fork - Hybrid Manual/Automated Workflow

Fork function blocks from Schneider Electric standard libraries into your custom library using a hybrid approach that combines the best of manual and automated workflows.

v7.2 ENHANCED - Production-Ready Reliability:

  • Manual fork in EAE GUI → Perfect HMI files (generated by EAE's designer)
  • Automated finalization → Single-command execution updates ALL references

- ✅ Root namespace updates - ✅ Cross-block references (FB/SubCAT in .fbt files) - ✅ HMI cross-references (fully qualified types in Designer.cs) - ✅ GUID generation + Registration - ✅ Transactional rollback - Automatic recovery from failures (v7.1) - ✅ UTF-8 encoding - Works on international Windows systems (v7.1) - 🆕 Pre-fork validation - Catches errors before manual fork in GUI (v7.2) - 🆕 Better error messages - Contextual help with recovery suggestions (v7.2) - 🆕 Resume capability - Gracefully handles interrupted forks (v7.2) - 🆕 Dependency auto-detection - Automatically suggests all SubCATs to fork (v7.2)

Why this approach?

  • Perfect HMI files - EAE's GUI generates flawless Designer.cs files
  • Complete automation - One command handles all namespace updates
  • Cross-reference handling - Automatically updates references between forked blocks
  • Fast - ~15 seconds per hierarchy (vs 3+ minutes manual editing)
  • User control - Full visibility in GUI during fork
  • Failure-safe - Auto-rollback protects your project from corruption
  • 🆕 Resumable - Interrupted forks can be resumed from last successful block

Separation of Concerns:

  • eae-fork (this skill): Finalize manually forked blocks (namespaces, GUIDs, registration)
  • eae-cat: Register CAT blocks in dfbproj AND csproj (when called with --register-only)
  • eae-composite-fb: Register composite blocks in dfbproj (when called with --register-only)
  • eae-basic-fb: Register basic blocks in dfbproj (when called with --register-only)
  • eae-adapter: Register adapters in dfbproj (when called with --register-only)
  • eae-datatype: Register data types in dfbproj (when called with --register-only)

Quick Start

Interactive Guided Workflow - Just tell the skill what you want:

You: Fork AnalogInput into SE.ScadapackWWW

Claude:
  📋 Analyzing AnalogInput...

  This block requires a 3-level hierarchy:
  1. AnalogInputBase (core logic)
  2. AnalogInputBaseExt (extended features)
  3. AnalogInput (full implementation)

  📝 Please fork these blocks in EAE GUI:

  Steps:
  1. Open EAE GUI
  2. Navigate to SE.App2CommonProcess library
  3. For each block, right-click → "Copy Block"
     ☐ AnalogInputBase → SE.ScadapackWWW
     ☐ AnalogInputBaseExt → SE.ScadapackWWW
     ☐ AnalogInput → SE.ScadapackWWW
  4. Reply 'done' when complete

You: done

Claude:
  🔧 Finalizing fork...
  ✓ Validated 3 blocks manually forked
  ✓ Updated namespaces in .fbt files (SE.ScadapackWWW)
  ✓ Updated namespaces in .cs files (15 files)
  ✓ Generated new GUIDs
  ✓ Registered in dfbproj/csproj

  ✅ Fork complete! Blocks ready to use in SE.ScadapackWWW.

What the skill does:

  1. 🔍 Analyzes block hierarchy and dependencies
  2. 📋 Guides you through manual fork in EAE GUI
  3. ⏸️ Waits for your confirmation
  4. 🔧 Executes finalization script - Single command updates everything:

- Root namespaces in .fbt files - Cross-block references (FB/SubCAT elements) - HMI namespaces in .cs files - HMI cross-references (fully qualified types) - New GUIDs for all blocks - Project registration (dfbproj/csproj)

  1. Reports complete summary with counts

Alternative: Manual Finalization

If you've already forked in EAE GUI:

/eae-fork --finalize AnalogInput

Triggers

TriggerDescription
/eae-forkPrimary invocation
fork block from libraryNatural language
copy block to custom libraryAlternative phrasing
migrate block namespaceNamespace-focused
customize EAE blockCustomization intent

CRITICAL: Fork Depth Selection

Before forking, ALWAYS ask the user about fork depth:

How deep should the fork go?

1. **Single block only** (Recommended for minor customization)
   - Fork only AnalogInput
   - Uses original library's AnalogInputBaseExt
   - Smallest footprint, easy to maintain

2. **Fork hierarchy** (Base → BaseExt → Full)
   - Fork AnalogInputBase, AnalogInputBaseExt, AND AnalogInput
   - Full control over the entire block chain
   - Best for significant modifications

3. **Fork with all SubCATs**
   - Fork hierarchy PLUS all SubCAT blocks (LimitAlarm, DeviationAlarm, etc.)
   - Maximum customization capability
   - Largest footprint, most maintenance

Which option do you prefer? (1/2/3)

How It Works - Streamlined Workflow (v7.0)

┌─────────────────────────────────────────────────────────────────┐
│      PHASE 1: ANALYZE & GUIDE (Automatic)                        │
├─────────────────────────────────────────────────────────────────┤
│ User: "Fork AnalogInput into SE.ScadapackWWW"                   │
│                                                                  │
│ Skill analyzes:                                                  │
│ 1. Identify block hierarchy (Base → BaseExt → Full)            │
│ 2. Detect dependencies (SubCATs, referenced blocks)             │
│ 3. Determine target library details                             │
│                                                                  │
│ Skill generates guided instructions:                             │
│ • List of blocks to fork (with checkboxes)                      │
│ • Step-by-step EAE GUI instructions                             │
│ • Clear confirmation prompt                                      │
│                                                                  │
│ Output: Checklist for user to follow                             │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│      PHASE 2: MANUAL FORK IN EAE GUI (User)                      │
├─────────────────────────────────────────────────────────────────┤
│ User performs fork using EAE's built-in functionality:           │
│                                                                  │
│ For each block in checklist:                                     │
│ 1. Open EAE GUI                                                  │
│ 2. Navigate to source library (e.g., SE.App2CommonProcess)      │
│ 3. Right-click block → "Copy Block"                             │
│ 4. Select target library (e.g., SE.ScadapackWWW)                │
│ 5. Wait for EAE to generate files                               │
│                                                                  │
│ EAE generates perfect files:                                     │
│ • IEC61499/{Block}/  (all .fbt, .cfg, .xml files)              │
│ • HMI/{Block}/       (perfect Designer.cs files)               │
│                                                                  │
│ ✅ Perfect HMI files (EAE's designer)                            │
│ ✅ All visual properties preserved                               │
│ ✅ No decompilation needed                                       │
│                                                                  │
│ User replies: "done"                                             │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│      PHASE 3: FINALIZE FORK - SINGLE COMMAND (Automatic)         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│ Command Executed:                                                │
│   python finalize_manual_fork.py \                              │
│       AnalogInputBase AnalogInputBaseExt AnalogInput \          │
│       LimitAlarm DeviationAlarm ROCAlarm \                      │
│       SE.ScadapackWWW                                            │
│                                                                  │
│ What the script does automatically:                              │
│                                                                  │
│ [1/4] VALIDATE MANUAL FORK                                       │
│       • Detect source namespace from existing files              │
│       • Check all blocks forked (IEC61499/ and HMI/)            │
│       • Detect block types (.cfg → CAT, etc.)                   │
│       • Verify file completeness                                │
│                                                                  │
│ [2/4] UPDATE NAMESPACES & CROSS-REFERENCES                       │
│       • Root declarations: Namespace="SE.ScadapackWWW"         │
│       • FB/SubCAT elements: Update refs to forked blocks        │
│       • HMI namespaces: Update Symbols/Faceplates namespaces    │
│       • HMI cross-refs: Update fully qualified type references  │
│       • Generate new GUIDs (12 total: 2 per block)             │
│                                                                  │
│ [3/4] REGISTER IN PROJECT                                        │
│       • Detect block type (CAT/Composite/Basic)                 │
│       • Call registration script for each block                  │
│       • dfbproj entries (Compile/None ItemGroups)               │
│       • csproj entries (CAT HMI files)                          │
│                                                                  │
│ [4/4] REPORT SUMMARY                                             │
│       • Successful: 6/6 blocks                                   │
│       • Cross-references updated: 24                             │
│       • HMI references updated: 18                               │
│                                                                  │
│ Output: "✅ All blocks finalized successfully!"                 │
│                                                                  │
│ Time: ~15 seconds (vs 3+ minutes manual editing)                │
└─────────────────────────────────────────────────────────────────┘

Why This Workflow?

AspectManual Fork + FinalizeOld Automated Approach
HMI Files✅ Perfect (EAE-generated)❌ Decompiled (format issues)
Complexity✅ Low (simple namespace update)❌ High (ILSpy, post-processing)
Reliability✅ 100% (proven EAE workflow)❌ ~70% (decompilation artifacts)
Speed✅ ~30 sec/block⚠️ ~2 min/block
User Control✅ Full visibility in GUI⚠️ Black box automation
Maintenance✅ Easy (140 lines of code)❌ Hard (500+ lines)

Phase 3 Detail: Registration by Block Type

CAT Blocks (most common):

/eae-cat --register-only {BlockName} {Namespace}
  │
  ├── dfbproj: Add Compile entries for .fbt, _HMI.fbt
  ├── dfbproj: Add None entries for .cfg, .offline.xml, .opcua.xml
  ├── csproj: Add Compile entries for HMI .cs files
  ├── csproj: Add EmbeddedResource entries for .resx, .xml
  └── Folders.xml: Add folder entry

Composite FB:

/eae-composite-fb --register-only {BlockName} {Namespace}
  │
  └── dfbproj: Add Compile entry for .fbt (IEC61499Type=Composite)

Basic FB:

/eae-basic-fb --register-only {BlockName} {Namespace}
  │
  └── dfbproj: Add Compile entry for .fbt (IEC61499Type=Basic)

Adapter:

/eae-adapter --register-only {BlockName} {Namespace}
  │
  └── dfbproj: Add Compile entry for .adp (IEC61499Type=Adapter)

DataType:

/eae-datatype --register-only {BlockName} {Namespace}
  │
  └── dfbproj: Add Compile entry for .dt (IEC61499Type=DataType)

eae-fork Responsibilities (Steps 1-5)

Step 1: Copy IEC61499 Files

Copy from source library to target:

SourceTarget
Libraries/{Lib}/Files/{Block}/{Project}/{Target}/IEC61499/{Block}/

IEC61499 Files to copy:

{Block}.fbt              - Main block definition (XML)
{Block}.cfg              - CAT configuration (links to HMI)
{Block}.doc.xml          - Documentation (optional)
{Block}_HMI.fbt          - HMI interface block
{Block}_CAT.offline.xml  - Offline parameters
{Block}_CAT.opcua.xml    - OPC-UA config
{Block}_HMI.offline.xml  - HMI offline parameters
{Block}_HMI.opcua.xml    - HMI OPC-UA config

Step 2: Decompile & Transform HMI Files (CRITICAL)

HMI files must be DECOMPILED from the source library DLL. Standard Schneider Electric libraries ship only compiled HMI DLLs - no source files exist in the Files/ directory for HMI.

SourceTarget
Libraries/{Lib}-{Ver}/HMI/{Lib}.HMI.dll (DECOMPILE){Project}/{Target}/HMI/{Block}/

Decompilation Process:

# Use the decompile_hmi.py script
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInputBase SE.ScadapackWWW ./output

# Or with hierarchy (multiple blocks)
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
    --forked-blocks AnalogInputBase AnalogInputBaseExt AnalogInput

What the decompilation does:

  1. Locates the HMI DLL in C:\ProgramData\Schneider Electric\Libraries\{Lib}-{Ver}\HMI\
  2. Decompiles using ILSpy CLI (ilspycmd)
  3. Finds symbol/faceplate classes in {Lib}.Symbols.{Block}/ and {Lib}.Faceplates.{Block}/ directories
  4. Splits decompiled classes into EAE format: .cnv.cs (main) + .cnv.Designer.cs (InitializeComponent)
  5. Updates namespaces according to the rules below
  6. Creates .cnv.resx and .cnv.xml files

HMI Files to copy (per symbol/faceplate):

{Block}.def.cs                    - Faceplate accessor definitions
{Block}.event.cs                  - Event argument classes
{Block}.Design.resx               - Design resources

{Block}_fpDefault.cnv.cs          - Faceplate implementation
{Block}_fpDefault.cnv.Designer.cs - Designer-generated code
{Block}_fpDefault.cnv.resx        - Faceplate resources

{Block}_fpParameter.cnv.cs        - Parameter faceplate
{Block}_fpParameter.cnv.Designer.cs
{Block}_fpParameter.cnv.resx

{Block}_fpTrend.cnv.cs            - Trend faceplate
{Block}_fpTrend.cnv.Designer.cs
{Block}_fpTrend.cnv.resx

{Block}_sDefault.cnv.cs           - Default symbol
{Block}_sDefault.cnv.Designer.cs
{Block}_sDefault.cnv.resx
{Block}_sDefault.cnv.xml          - Symbol XML (ONLY for symbols)

{Block}_sVertical.cnv.cs          - Vertical symbol
{Block}_sVertical.cnv.Designer.cs
{Block}_sVertical.cnv.resx
{Block}_sVertical.cnv.xml

{Block}_sDisplayPv.cnv.cs         - Display PV symbol
{Block}_sDisplayPv.cnv.Designer.cs
{Block}_sDisplayPv.cnv.resx
{Block}_sDisplayPv.cnv.xml

{Block}_sInstanceName.cnv.cs      - Instance name symbol
{Block}_sInstanceName.cnv.Designer.cs
{Block}_sInstanceName.cnv.resx
{Block}_sInstanceName.cnv.xml

Important: Faceplates (fp*) do NOT have .cnv.xml files. Symbols (s*) DO have .cnv.xml files.

Step 3: Update Namespace & GUID in .fbt Files

<!-- BEFORE (source) -->
<FBType GUID="422cce07-335e-414d-823c-03c2d1ac0ef6"
        Name="AnalogInput" Namespace="SE.App2CommonProcess">

<!-- AFTER (forked) -->
<FBType GUID="a59ec74d-736e-42ab-a3ff-de74c9003156"
        Name="AnalogInput" Namespace="SE.ScadapackWWW">

Sub-block namespace rules:

Block TypeAction
Forked blocks (in hierarchy)Update to target namespace
Original library blocksKEEP original namespace
Adapter interfacesKEEP original namespace
DataTypesKEEP original namespace
<!-- MUST Update (forked blocks) -->
<FB Name="analogInputBaseExt" Type="AnalogInputBaseExt"
    Namespace="SE.ScadapackWWW" />

<!-- MUST KEEP (original library blocks) -->
<FB Name="rawPv" Type="aISignal" Namespace="SE.App2Base" />
<FB Name="control" Type="analogInputLogic" Namespace="SE.App2CommonProcess" />
<Adapter Name="IPv" Type="IAnalog" Namespace="SE.App2Base" />

Step 4: Update .cfg File

The .cfg file links the CAT block to its HMI symbols. Update all paths:

<CAT Name="AnalogInputBase"
     CATFile="AnalogInputBase\AnalogInputBase.fbt"
     SymbolDefFile="..\HMI\AnalogInputBase\AnalogInputBase.def.cs"
     SymbolEventFile="..\HMI\AnalogInputBase\AnalogInputBase.event.cs"
     DesignFile="..\HMI\AnalogInputBase\AnalogInputBase.Design.resx"
     DocFile="AnalogInputBase\AnalogInputBase.doc.xml"
     Folder=".SignalProcessing.AnalogInput">

  <HMIInterface Name="IThis" FileName="AnalogInputBase\AnalogInputBase_HMI.fbt">
    <Symbol Name="fpDefault"
            FileName="..\HMI\AnalogInputBase\AnalogInputBase_fpDefault.cnv.cs"
            IsFaceplate="true">
      <DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_fpDefault.cnv.Designer.cs</DependentFiles>
      <DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_fpDefault.cnv.resx</DependentFiles>
    </Symbol>
    <Symbol Name="sDefault"
            FileName="..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.cs">
      <DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.Designer.cs</DependentFiles>
      <DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.resx</DependentFiles>
      <DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.xml</DependentFiles>
    </Symbol>
    <!-- More symbols... -->
  </HMIInterface>

  <Plugin Name="Plugin=OfflineParametrizationEditor;..."
          Project="SE.ScadapackWWW"  <!-- UPDATE THIS -->
          Value="AnalogInputBase\AnalogInputBase_CAT.offline.xml" />
</CAT>

Step 5: Update HMI Namespaces (CRITICAL - Complex Rules)

HMI files contain multiple categories of namespace references that require different handling:

Namespace Reference Categories

CategoryPatternActionExample
Block-specific (this block){Lib}.Symbols.{Block}, {Lib}.Faceplates.{Block}UPDATE to targetSE.App2CommonProcess.Symbols.AnalogInputBaseSE.ScadapackWWW.Symbols.AnalogInputBase
Cross-block (forked block){Lib}.Symbols.{OtherForkedBlock}UPDATE if in forked setWhen forking hierarchy, update AnalogInputBase refs in AnalogInput
Cross-block (not forked){Lib}.Symbols.{NonForkedBlock}KEEP originalKeep SE.App2CommonProcess.Symbols.Motor if Motor not forked
SupportClasses{Lib}.SupportClassesALWAYS KEEPSE.App2CommonProcess.SupportClasses - contains shared utilities
Base librarySE.App2Base.*ALWAYS KEEPSE.App2Base.Faceplates, SE.App2Base.Symbols, etc.
FrameworkSystem.*, NxtControl.*ALWAYS KEEPFramework namespaces never change

Example: Using Directives in sDefault.cs

// From AnalogInputBase/sDefault.cs (decompiled)

// KEEP - Framework namespaces
using System;
using NxtControl.GuiFramework;

// KEEP - Base library (SE.App2Base)
using SE.App2Base.Faceplates;
using SE.App2Base.Graphics;
using SE.App2Base.SupportClasses;
using SE.App2Base.Symbols;

// UPDATE - Block-specific (this block is being forked)
using SE.App2CommonProcess.Faceplates.AnalogInputBase;
// → SE.ScadapackWWW.Faceplates.AnalogInputBase

// KEEP - SupportClasses (shared utilities, NOT block-specific)
using SE.App2CommonProcess.SupportClasses;
// Contains: AnalogInputUnit, MotorAppearance, ValveAppearance, etc.

namespace SE.App2CommonProcess.Symbols.AnalogInputBase;
// → namespace SE.ScadapackWWW.Symbols.AnalogInputBase;

Cross-Block References (Hierarchy Forks)

When forking a hierarchy (e.g., AnalogInput → AnalogInputBaseExt → AnalogInputBase), child blocks embed parent symbols:

// From AnalogInput/sDefault.cs (decompiled)

// UPDATE - Cross-block reference (AnalogInputBase IS in the forked set)
using SE.App2CommonProcess.Symbols.AnalogInputBase;
// → SE.ScadapackWWW.Symbols.AnalogInputBase

// Fully qualified type in field declaration
private SE.App2CommonProcess.Symbols.AnalogInputBase.sDefault analogFunction;
// → SE.ScadapackWWW.Symbols.AnalogInputBase.sDefault

// Instantiation
analogFunction = new SE.App2CommonProcess.Symbols.AnalogInputBase.sDefault();
// → new SE.ScadapackWWW.Symbols.AnalogInputBase.sDefault();

SupportClasses - Why They Must Be Preserved

The SupportClasses namespace contains library-wide utility classes shared across all blocks:

SE.App2CommonProcess.SupportClasses/
├── AnalogInputUnit.cs        # Used by AnalogInput symbols
├── AnalogOutputUnit.cs       # Used by AnalogOutput symbols
├── MotorAppearance.cs        # Used by Motor symbols
├── ValveAppearance.cs        # Used by Valve symbols
├── PIDUnit.cs                # Used by PID symbols
├── BitExtensions.cs          # Utility methods
├── DynamicPropertyGrid.cs    # UI helpers
└── ... (60+ shared classes)

These classes are NOT part of any specific block and should NEVER have their references updated.

Files requiring namespace update:

  • {Block}.def.cs - Multiple namespaces (Faceplates and Symbols)
  • {Block}.event.cs - Multiple namespaces
  • {Block}_*.cnv.cs - Single namespace per file (plus cross-block references)

What eae-fork Does vs What eae-cat Does

eae-fork (File Transformation)

TaskDescription
Copy IEC61499 files.fbt, .cfg, .offline.xml, .opcua.xml
Copy HMI files.def.cs, .event.cs, .cnv.*, .Design.resx
Update namespacesIn .fbt and .cs files
Generate new GUIDsFor all forked .fbt files
Update .cfg pathsSymbolDefFile, SymbolEventFile, etc.

eae-cat (Project Registration)

TaskDescription
dfbproj registration3 ItemGroups (None, Compile, Content)
csproj registrationCompile, None, EmbeddedResource items
Folders.xml updateCAT folder entries
ValidationVerify block appears in library browser

Why this separation?

  • eae-fork handles file content transformation (namespace, GUID)
  • eae-cat handles project structure (registration, dependencies)
  • Each skill has clear, testable responsibilities

Commands

CommandDescription
/eae-fork {Block} from {Lib} to {Target}Fork a block (asks about depth)
/eae-fork --list {Lib}List blocks in source library
/eae-fork --hierarchy {Block}Fork block with Base/BaseExt chain
/eae-fork --with-deps {Block}Fork block with all dependencies
/eae-fork --dry-runShow what would be forked

Scripts

Detect Block Type (Orchestration)

The detect_block_type.py script examines source library files to determine block type for orchestration.

# Basic usage
python scripts/detect_block_type.py <block_name> <library_name>

# Examples
python scripts/detect_block_type.py AnalogInput SE.App2CommonProcess
# Output: Detected CAT block, sub-skill: eae-cat

python scripts/detect_block_type.py MyLogicFB SE.App2Base
# Output: Detected BASIC block, sub-skill: eae-basic-fb

# JSON output for automation
python scripts/detect_block_type.py AnalogInput SE.App2CommonProcess --json

# Verbose output with evidence
python scripts/detect_block_type.py AnalogInput SE.App2CommonProcess --verbose

Detection Logic:

Block TypeDetection Criteria
CATHas .cfg file with <HMIInterface> elements
Composite.fbt with Format="2.0" and <FBNetwork>, no <BasicFB>
Basic.fbt with <BasicFB> element
AdapterHas .adp file
DataTypeHas .dt file

Exit Codes:

CodeMeaning
0Success - type detected
1Block not found
2Unable to determine type

Pre-flight Check

Validate prerequisites before fork operations to catch errors early.

# Basic usage
python scripts/preflight_check.py <block_name> <source_library> <target_library>

# Examples
python scripts/preflight_check.py AnalogInput SE.App2CommonProcess SE.ScadapackWWW

# Allow overwriting existing target block
python scripts/preflight_check.py --allow-overwrite AnalogInput SE.App2CommonProcess SE.ScadapackWWW

# JSON output for automation
python scripts/preflight_check.py --json Motor SE.App2CommonProcess SE.ScadapackWWW

What it checks:

CheckDescription
Source libraryLibrary exists in standard locations
Source blockBlock folder/files exist in source
Block typeDetects CAT/Composite/Basic/Adapter/DataType
Source filesRequired files present for block type
Target libraryTarget exists in project
Target conflictBlock doesn't already exist in target
dfbproj existsTarget has valid dfbproj file

Exit Codes:

CodeMeaning
0Pre-flight passed, ready to fork
1Error (missing arguments, etc.)
10Pre-flight failed (prerequisites not met)
11Target exists (use --allow-overwrite)

Decompile HMI (Primary Script)

The decompile_hmi.py script extracts full HMI functionality from compiled library DLLs.

# Basic usage: decompile HMI for a single block
python scripts/decompile_hmi.py <source_lib> <block_name> <target_namespace> <output_dir>

# Example: Decompile AnalogInputBase HMI
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInputBase SE.ScadapackWWW \
    "C:\Project\SE.ScadapackWWW\HMI"

# Hierarchy fork: update cross-references between forked blocks
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
    --forked-blocks AnalogInputBase AnalogInputBaseExt AnalogInput

# Use existing decompiled directory (skip re-decompilation)
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
    --decompiled-dir C:\temp\decompiled-hmi

# Keep decompiled files for inspection
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
    --keep-decompiled

Requirements:

  • ILSpy CLI (ilspycmd) - Install with: dotnet tool install -g ilspycmd
  • Python 3.8+
  • Standard library only (no external dependencies)

Output Structure:

{output_dir}/{BlockName}/
├── {BlockName}.def.cs              # Faceplate/symbol partial class definitions
├── {BlockName}.event.cs            # Event argument classes
├── {BlockName}.Design.resx         # Design resources
├── {BlockName}_fpDefault.cnv.cs    # Faceplate main code
├── {BlockName}_fpDefault.cnv.Designer.cs  # InitializeComponent
├── {BlockName}_fpDefault.cnv.resx  # Faceplate resources
├── {BlockName}_sDefault.cnv.cs     # Symbol main code
├── {BlockName}_sDefault.cnv.Designer.cs   # InitializeComponent
├── {BlockName}_sDefault.cnv.resx   # Symbol resources
├── {BlockName}_sDefault.cnv.xml    # Symbol mapping (symbols only)
└── ... (more symbols/faceplates)

Exit Codes:

CodeMeaning
0Success
1Error (library not found, decompilation failed, etc.)

Fork Block

# Fork files and update namespaces (Steps 1-4 only)
python scripts/fork_block.py fork AnalogInput SE.App2CommonProcess SE.ScadapackWWW

# Fork with hierarchy
python scripts/fork_block.py fork AnalogInput SE.App2CommonProcess SE.ScadapackWWW --hierarchy

# List blocks
python scripts/fork_block.py list SE.App2CommonProcess

Validate Fork (Files Only)

# Validate namespace updates (NOT dfbproj registration)
python scripts/validate_fork.py SE.ScadapackWWW AnalogInput

Namespace Update Rules

MUST Update (Forked Blocks)

<!-- ROOT ELEMENT: Always update -->
<FBType Name="AnalogInput" Namespace="SE.ScadapackWWW">

<!-- SUB-BLOCKS that are ALSO forked: Update -->
<FB Name="analogInputBaseExt" Type="AnalogInputBaseExt"
    Namespace="SE.ScadapackWWW" />

MUST KEEP (Original Library References)

<!-- Blocks from original libraries: Keep namespace -->
<FB Name="rawPv" Type="aISignal" Namespace="SE.App2Base" />

<!-- Adapter interfaces: Always keep original -->
<Adapter Name="IPv" Type="IAnalog" Namespace="SE.App2Base" />

<!-- DataTypes from original libraries: Keep -->
<VarDeclaration Name="Status" Type="Status" Namespace="SE.App2Base" />

Block Hierarchy Pattern

EAE blocks follow a three-tier hierarchy:

BlockBase          → BlockBaseExt         → Block
(core logic)         (extended features)    (complete)

Example:
AnalogInputBase    → AnalogInputBaseExt   → AnalogInput

Anti-Patterns

AvoidWhyInstead
Registering in dfbproj from eae-forkDuplicates eae-cat logicDelegate to eae-cat
Creating HMI stubs instead of decompilingStubs lack visual functionalityUse decompile_hmi.py
Changing original library namespace referencesBreaks adaptersKeep original namespaces
Reusing source GUIDConflicts with originalGenerate new GUID
Not asking about fork depthWrong blocks forkedAlways clarify with user
Updating SupportClasses referencesBreaks shared utilitiesKeep SE.{Lib}.SupportClasses

Troubleshooting

IssueCauseSolution
Block not visible in librarydfbproj not updatedRun eae-cat to register
HMI exceptionsMissing or invalid HMI filesRe-run decompile_hmi.py
Adapter errorsWrong namespaceKeep adapter namespaces as SE.App2Base
Build errorsIncomplete hierarchyUse --hierarchy flag
ILSpy not foundilspycmd not installeddotnet tool install -g ilspycmd
Empty symbol outputBlock not in decompiled DLLCheck library path and block name
Missing SupportClassesNamespace incorrectly updatedKeep SE.{Lib}.SupportClasses as-is

Files Created by eae-fork

IEC61499 Files

FileChanges
{Block}.fbtNamespace, new GUID, sub-block references
{Block}.cfgSymbolDefFile, SymbolEventFile, DesignFile, DocFile, Plugin Project=
{Block}.doc.xmlCopy as-is
{Block}_HMI.fbtNamespace update, new GUID
{Block}_CAT.offline.xmlCopy as-is
{Block}_CAT.opcua.xmlCopy as-is
{Block}_HMI.offline.xmlCopy as-is
{Block}_HMI.opcua.xmlCopy as-is

HMI Files (All copied and namespace-updated)

FileChanges
{Block}.def.csNamespace update (multiple namespaces)
{Block}.event.csNamespace update (multiple namespaces)
{Block}.Design.resxCopy as-is
{Block}_fp*.cnv.csNamespace update
{Block}_fp*.cnv.Designer.csNamespace update
{Block}_fp*.cnv.resxCopy as-is
{Block}_s*.cnv.csNamespace update
{Block}_s*.cnv.Designer.csNamespace update
{Block}_s*.cnv.resxCopy as-is
{Block}_s*.cnv.xmlCopy as-is

Files NOT created by eae-fork (handled by eae-cat):

  • {Lib}.dfbproj - Project registration entries
  • {Lib}.HMI.csproj - HMI project registration entries
  • General/Folders.xml - CAT folder entries

HMI Decompilation Deep Dive

Why Decompilation is Required

Standard Schneider Electric libraries (SE.App2Base, SE.App2CommonProcess, etc.) ship with:

  • Source files for IEC61499 blocks (.fbt, .cfg, etc.) in Files/ directory
  • Compiled DLLs for HMI components in HMI/ directory
  • No source files for HMI symbols and faceplates

This means to fork a block with full HMI functionality, we must decompile the HMI DLL.

Decompilation Architecture

┌─────────────────────────────────────────────────────────────────────┐
│ Library: C:\ProgramData\Schneider Electric\Libraries\               │
│          SE.App2CommonProcess-25.0.1.5\                             │
├─────────────────────────────────────────────────────────────────────┤
│ Files/AnalogInputBase/        │ HMI/SE.App2CommonProcess.HMI.dll   │
│ ├── AnalogInputBase.fbt       │ (COMPILED - contains all HMI)      │
│ ├── AnalogInputBase.cfg       │                                     │
│ └── ...                       │                                     │
│ (SOURCE AVAILABLE)            │ (MUST DECOMPILE)                    │
└─────────────────────────────────────────────────────────────────────┘
                                          │
                                          ▼ ILSpy Decompile
┌─────────────────────────────────────────────────────────────────────┐
│ Decompiled Output (temp directory):                                  │
│ ├── SE.App2CommonProcess.Symbols.AnalogInputBase/                   │
│ │   ├── sDefault.cs           ← Combined class file                 │
│ │   ├── sVertical.cs                                                │
│ │   ├── sDisplayPv.cs                                               │
│ │   └── sInstanceName.cs                                            │
│ ├── SE.App2CommonProcess.Faceplates.AnalogInputBase/                │
│ │   ├── fpDefault.cs          ← Combined class file                 │
│ │   ├── fpParameter.cs                                              │
│ │   └── fpTrend.cs                                                  │
│ └── (resource files, mappings, etc.)                                │
└─────────────────────────────────────────────────────────────────────┘
                                          │
                                          ▼ Transform & Split
┌─────────────────────────────────────────────────────────────────────┐
│ EAE-Compatible Output:                                               │
│ {Project}/SE.ScadapackWWW/HMI/AnalogInputBase/                      │
│ ├── AnalogInputBase.def.cs            ← Partial class definitions   │
│ ├── AnalogInputBase.event.cs          ← Event arguments             │
│ ├── AnalogInputBase.Design.resx       ← Design resources            │
│ ├── AnalogInputBase_sDefault.cnv.cs   ← Main code (namespace only)  │
│ ├── AnalogInputBase_sDefault.cnv.Designer.cs  ← InitializeComponent │
│ ├── AnalogInputBase_sDefault.cnv.resx         ← Resources           │
│ ├── AnalogInputBase_sDefault.cnv.xml          ← Symbol mapping      │
│ └── ... (more symbols/faceplates)                                   │
└─────────────────────────────────────────────────────────────────────┘

Class File Splitting

ILSpy produces single-file classes. EAE requires split files:

Decompiled (ILSpy output):

// sDefault.cs - COMBINED
using System;
using NxtControl.GuiFramework;

namespace SE.App2CommonProcess.Symbols.AnalogInputBase;

public class sDefault : SEAppLibHMISymbol
{
    private AIFunctionName aIFunctionName;
    private AnalogValue analogValue;

    public sDefault()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        this.aIFunctionName = new AIFunctionName();
        this.analogValue = new AnalogValue();
        this.aIFunctionName.Location = new Point(0, 0);
        // ... 100+ lines of visual setup
    }
}

EAE format (split):

// AnalogInputBase_sDefault.cnv.cs - MAIN
using NxtControl.GuiFramework;
using SE.App2Base.Symbols;

namespace SE.ScadapackWWW.Symbols.AnalogInputBase
{
    public partial class sDefault : SEAppLibHMISymbol
    {
        public sDefault()
        {
            InitializeComponent();
        }
    }
}
// AnalogInputBase_sDefault.cnv.Designer.cs - DESIGNER
using System.Drawing;
using System.ComponentModel;
using NxtControl.Drawing;
using NxtControl.GuiFramework;

namespace SE.ScadapackWWW.Symbols.AnalogInputBase
{
    partial class sDefault
    {
        private void InitializeComponent()
        {
            this.aIFunctionName = new AIFunctionName();
            this.analogValue = new AnalogValue();
            // ... full visual setup code
        }
    }
}

ILSpy Installation

# Install ILSpy CLI globally
dotnet tool install -g ilspycmd

# Verify installation
ilspycmd --version

# Common install location (Windows)
~/.dotnet/tools/ilspycmd.exe

Manual Decompilation (for Debugging)

# Decompile entire HMI DLL
ilspycmd "C:\ProgramData\Schneider Electric\Libraries\SE.App2CommonProcess-25.0.1.5\HMI\SE.App2CommonProcess.HMI.dll" -p -o C:\temp\decompiled

# Explore output structure
dir /s C:\temp\decompiled\SE.App2CommonProcess.Symbols.*

Related Skills

SkillRelationship
eae-catCALL AFTER FORK for CAT registration
eae-composite-fbCall after fork for composite registration
eae-basic-fbCall after fork for basic FB registration
eae-se-processFind source blocks to fork
eae-runtime-baseFind sub-block types

Changelog

v7.2.0 (Current)

  • MAJOR ENHANCEMENT: Resume capability for interrupted forks

- NEW: Session state tracking (.eae-fork-state.json) - Tracks completion progress - NEW: load_session_state(), save_session_state(), clear_session_state() - Session management - NEW: prompt_resume_or_restart() - Interactive resume/restart decision - HOW IT WORKS: Saves state after each successful block, allows resume on interruption - BENEFIT: Never lose progress on large hierarchies (9+ blocks) - USE CASE: System crashes, Ctrl+C interruptions, file access errors - all recoverable

  • MAJOR ENHANCEMENT: Dependency auto-detection

- NEW: detect_dependencies.py script - Parses .cfg files to find SubCAT dependencies - NEW: detect_block_hierarchy() - Detects Base → BaseExt → Full hierarchies - NEW: parse_subcats_from_cfg() - Extracts SubCAT Type references from XML - HOW IT WORKS: Recursively analyzes .cfg files, builds complete dependency tree - BENEFIT: Automatically suggests all blocks to fork (hierarchy + SubCATs) - EXAMPLE: MotorVs → detects 3 hierarchy blocks + 6 SubCATs = 9 total blocks - USE CASE: python detect_dependencies.py SE.App2CommonProcess MotorVs --include-hierarchy

  • ENHANCEMENT: Pre-fork validation

- NEW: validate_pre_fork() - Checks source blocks exist BEFORE manual fork - BENEFIT: Prevents wasted time in GUI if blocks don't exist - EXIT CODES: 0=ready, 10=validation failed

  • ENHANCEMENT: Better error messages

- NEW: Custom exception classes (ForkValidationError, NamespaceUpdateError, RegistrationError) - NEW: print_helpful_error() - Contextual error messages with recovery suggestions - BENEFIT: Clear guidance on fixing errors instead of cryptic stack traces - EXAMPLES: File permission errors → suggests closing editors and removing read-only

  • UX IMPROVEMENTS:

- Clear session ID display on resume prompts - Block mismatch detection (prevents resuming wrong fork) - Stale session warnings (>24 hours old) - Progress display (X/Y blocks completed) - Dependency tree visualization (shows SubCAT relationships)

  • TESTED: Validated on MotorVS fork (detected all 9 blocks correctly)

v7.1.0

  • CRITICAL ENHANCEMENT: Transactional rollback protection

- NEW: ForkTransaction context manager - Automatic backup/restore on failures - BENEFIT: Zero risk of project corruption from partial failures - HOW IT WORKS: Backs up all blocks before changes, auto-restores on any error - IMPACT: Protects against mid-execution crashes, file access errors, etc.

  • CRITICAL FIX: UTF-8 encoding for international Windows systems

- FIXED: Unicode character errors (, , caused crashes on CP1252 encoding) - SOLUTION: Force UTF-8 output + ASCII-safe symbols ([OK], [ERROR], [SUCCESS]) - BENEFIT: Works reliably on French, German, Chinese, and all non-English Windows

  • DOCUMENTATION: Removed outdated v5.0 workflow section (was confusing)
  • RELIABILITY: 100% failure-safe with automatic recovery
  • TESTED: Validated on MotorVS fork (9 blocks, successful rollback testing)

v7.0.0

  • MAJOR ENHANCEMENT: Fully automated cross-reference handling

- NEW: update_cross_block_references() - Updates FB/SubCAT Namespace attributes for blocks in forked set - NEW: update_hmi_cross_references() - Updates fully qualified type references in HMI Designer.cs files - NEW: detect_source_namespace() - Automatically detects source namespace from .fbt files - IMPROVED: Workflow now single-command execution (no manual file editing) - IMPROVED: Script infers forked blocks from arguments (no --forked-blocks flag needed)

  • PERFORMANCE: ~15 seconds for hierarchy (vs 3+ minutes manual editing in v6.0)
  • RELIABILITY: 100% systematic updates (no missed references)
  • BENEFITS:

- ✅ Zero manual file editing required - ✅ Automatic cross-block reference updates (IEC61499) - ✅ Automatic HMI cross-reference updates (Designer.cs) - ✅ Clear progress reporting and summary - ✅ Maintains all v6.0 benefits (perfect HMI files, simple workflow)

v6.0.0

  • PARADIGM SHIFT: Hybrid manual/automated workflow

- Manual fork in EAE GUI → perfect HMI files (generated by EAE's designer) - Automated finalization → namespace updates + GUID generation + registration

  • REMOVED: Decompilation complexity

- Deleted decompile_hmi.py (no longer needed) - Deleted generate_hmi_from_reflection.py (experimental, didn't work) - Removed ILSpy CLI dependency - Removed pythonnet dependency

  • NEW: finalize_manual_fork.py script

- Validates manual fork completed in GUI - Updates namespaces in .fbt and .cs files - Generates new GUIDs - Registers block in dfbproj/csproj - ~140 lines vs 500+ lines of decompilation code

  • IMPROVED: Reliability

- ✅ 100% success rate (EAE-generated HMI files) - ✅ Simple & maintainable (namespace updates only) - ✅ Fast (~30 seconds per block) - ✅ User control (full visibility in GUI)

  • BREAKING CHANGE: Workflow now requires manual fork in EAE GUI first

- Benefit: Perfect HMI files guaranteed - Trade-off: User must perform fork in GUI (30 seconds) - Net result: Simpler, more reliable overall workflow

v5.1.0

  • CRITICAL FIX: Complete HMI file generation (SUPERSEDED by v6.0)

- Modified fork_block.py::extract_decompiled_hmi() to call standalone decompile_hmi.py as subprocess - Now creates ALL required HMI files: .cnv.cs, .cnv.Designer.cs, .cnv.resx, .cnv.xml, .Design.resx - Eliminated code duplication between fork_block.py and decompile_hmi.py - Fixed EAE GUI errors "Unable to load Designer.cs/resx" files

  • CRITICAL FIX: Conditional aspmap.xml registration

- Modified register_dfbproj.py to check if aspmap.xml exists before adding to dfbproj - Only SE.App2CommonProcess blocks have aspmap.xml, SE.App2Base blocks don't - Eliminated "Solution Integrity" warnings for missing aspmap.xml files

  • IMPROVED: Files now match manual fork structure exactly
  • TESTED: All symbols and faceplates open correctly in EAE GUI without errors
  • NOTE: This version attempted to solve HMI generation via decompilation - v6.0 takes simpler approach

v5.0.0

  • MAJOR: Automatic orchestration workflow

- eae-fork now detects block type and automatically calls appropriate registration sub-skill - Users no longer need to manually run registration skills after forking - Added detect_block_type.py script for block type detection

  • NEW: Block type detection examines source files to determine:

- CAT (has .cfg with HMIInterface) - Composite (FBNetwork, no BasicFB) - Basic (has BasicFB) - Adapter (has .adp file) - DataType (has .dt file)

  • NEW: Orchestration routing to sub-skills:

- CAT → /eae-cat --register-only - Composite → /eae-composite-fb --register-only - Basic → /eae-basic-fb --register-only - Adapter → /eae-adapter --register-only - DataType → /eae-datatype --register-only

  • IMPROVED: Complete workflow in single command

v4.0.0

  • MAJOR: Full HMI decompilation workflow

- Added decompile_hmi.py script for extracting HMI from compiled DLLs - Uses ILSpy CLI (ilspycmd) for decompilation - Splits decompiled classes into EAE format (.cnv.cs + .cnv.Designer.cs) - Preserves full visual implementation (not stubs)

  • NEW: Decompilation process:

1. Locate HMI DLL in library folder 2. Decompile using ILSpy to temp directory 3. Find symbol/faceplate classes for the target block 4. Extract InitializeComponent to Designer file 5. Update namespaces with proper categorization rules 6. Generate .resx and .cnv.xml files

  • IMPROVED: Cross-block reference handling for hierarchy forks

- --forked-blocks flag to specify all blocks being forked - Updates cross-references only for blocks in forked set

  • REQUIREMENT: ILSpy CLI (dotnet tool install -g ilspycmd)

v3.1.0

  • CRITICAL FIX: Smart HMI namespace handling with proper reference categorization

- Block-specific namespaces (Symbols/Faceplates.{Block}): UPDATE if block is forked - Cross-block references: UPDATE only if referenced block is in forked set - SupportClasses: ALWAYS PRESERVE (library-wide shared utilities) - Base library (SE.App2Base.*): ALWAYS PRESERVE - Framework (System.*, NxtControl.*): ALWAYS PRESERVE

  • ENHANCED: Cross-block reference handling for hierarchy forks

- When forking AnalogInput hierarchy, AnalogInput's reference to AnalogInputBase.sDefault is properly updated - Fully qualified type references and instantiations are updated

  • DOCUMENTED: Comprehensive namespace reference categories with examples
  • IMPROVED: Better logging of preserved library references

v3.0.0

  • CRITICAL FIX: HMI files must be COPIED from source, not generated

- Insight from manual fork analysis in EAE GUI - HMI files contain complete implementations with designer code

  • EXPANDED: eae-fork now handles Steps 1-5:

- Step 1: Copy IEC61499 files - Step 2: Copy HMI files (NEW - from source library) - Step 3: Update namespaces in .fbt files - Step 4: Update .cfg file (expanded: all path attributes) - Step 5: Update HMI namespaces in .cs files

  • DOCUMENTED: Complete file list from manual fork analysis

- IEC61499 files: 8 file types - HMI files: Up to 28 files per block (varies by symbols/faceplates)

  • DOCUMENTED: Detailed .cfg file structure with all required attributes
  • CLARIFIED: eae-cat handles project registration only (dfbproj, csproj, Folders.xml)

v2.1.0

  • Clear separation of concerns between eae-fork and eae-cat
  • Removed dfbproj registration from eae-fork (delegated to eae-cat)

v2.0.0

  • Added fork depth user interaction question
  • Added dfbproj registration (now moved to eae-cat)
  • Added HMI file generation (now moved to eae-cat)

v1.0.0

  • Initial release
  • Basic file copy and namespace update

适合场景

01

用户想查找某类 Agent Skill 时

02

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

03

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

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

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

能力 4

补充不同宿主或平台的使用分布数据

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

平台分布

Claude Code

29.04%
按下载量换算71

OpenCode

23.16%
按下载量换算57

windsurf

18.55%
按下载量换算46

trae

15.1%
按下载量换算37

Cursor

7.72%
按下载量换算19

Codex

3.34%
按下载量换算8

安全审计

暂无安全审计结果可展示。

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

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

来源信息

继续浏览同类 Skills