Skill: junqianglu3-netizen/jingyi-module (version 0.1.0)

--- name: jingyi-module description: Help users use 精易模块 in 易语言. Search command names, fetch official docs, and generate directly runnable 易语言 code that the user can copy. homepage: https://ec.ijingyi.com/sub.htm user-invocable: true metadata: {"openclaw":{"requires":{"bins":["python"]},"homepage":"https://ec.ijingyi.com/sub.htm"}} --- # Jingyi Module Skill Use this skill when the user asks for: - 精易模块应该用哪个命令 - 某个精易模块命令的参数、返回值、备注 - 一段可以直接复制运行的易语言代码 This skill is designed for retrieval first, then code generation. ## Goals - Quickly find the most relevant 精易模块命令 - Pull the official command content by id or name - Generate directly runnable 易语言 code - Avoid inventing commands or parameters ## Workflow 1. Search candidate commands first 2. Fetch the full command doc for the best candidates 3. Write code only after confirming the signature and behavior 4. Prefer concise explanation plus one runnable code block ## Search commands Run: ```powershell python "{baseDir}/scripts/search_jingyi.py" "随机汉字" --top 8 ``` Examples: ```powershell python "{baseDir}/scripts/search_jingyi.py" "随机汉字" --top 8 python "{baseDir}/scripts/search_jingyi.py" "选择字体" --top 8 python "{baseDir}/scripts/search_jingyi.py" "取月末" --top 8 ``` The result includes: - `id` - `name` - `canonical_path` - `cmdtype` - `score` - `summary` ## Fetch full command docs Run: ```powershell python "{baseDir}/scripts/fetch_jingyi_doc.py" --id 1109 ``` or: ```powershell python "{baseDir}/scripts/fetch_jingyi_doc.py" --name "文本_取随机汉字" ``` This returns the official document JSON. For three known official empty-response nodes, the script includes built-in补录 content: - `时间_取月末` - `文本_取随机汉字` - `选择字体` ## Output rules - Output runnable 易语言 code with `.版本 2` when code is requested - Do not mention IDE automation - Do not invent missing parameters or return types - If there are multiple candidate commands, name the chosen command before the code - When uncertain, keep the explanation to one short sentence ## Good response shape One short paragraph: - what command is being used - why it matches the request Then one code block: ```text .版本 2 ... ``` ## Notes - The local index is a compact retrieval index, not the full manual - The fetch script uses the official endpoint: - `https://ec.ijingyi.com/plugin.php?id=plugin1&`

path: GITHUB_INTRO.zh-CN.md
content: # 精易模块 OpenClaw 技能

一个面向 **易语言 / 精易模块** 的 OpenClaw 技能包。

它的目标很直接：

- 帮模型快速检索精易模块命令
- 拉取对应命令的官方说明
- 基于真实命令签名生成 **可直接复制运行** 的易语言代码

这不是一个 IDE 自动化工具，而是一个 **对话式代码生成技能**。

你可以把它接到任何支持 OpenClaw / Skills / RAG 风格流程的系统里，让模型在回答这类问题时更可靠：

- “精易模块怎么随机取汉字？”
- “打开文件对话框用哪个命令？”
- “帮我写一段精易模块代码，获取月末日期并显示出来”
- “用精易模块实现字体选择框”

## 这个技能解决什么问题

精易模块命令很多，直接靠模型记忆很容易：

- 记错命令名
- 编错参数
- 混淆返回值
- 写出根本不存在的调用方式

这个技能通过“**先检索，再生成**”的方式，尽量避免这些问题。

## 核心能力

- 内置精易模块命令检索索引
- 支持按命令名、关键词、路径检索
- 支持按命令 id 或名称抓取官方说明
- 对 3 个官方空响应命令做了内置补录
- 生成结果以 **易语言可复制代码** 为目标

## 适合谁

- 想做“易语言大模型”的开发者
- 想让 AI 正确使用精易模块的用户
- 想做精易模块问答、命令搜索、代码助手的人

## 仓库内容

- `SKILL.md`：技能说明
- `manifest.yaml`：技能元数据
- `data/command_index.jsonl`：命令检索索引
- `scripts/search_jingyi.py`：命令搜索脚本
- `scripts/fetch_jingyi_doc.py`：官方文档抓取脚本
- `scripts/build_command_index.py`：索引重建脚本

## 使用方式

1. 先让模型用技能检索候选命令
2. 再抓取对应命令的完整说明
3. 最后生成一段可直接复制的 `.版本 2` 易语言代码

## 适合搭配

- OpenClaw Skills
- RAG 检索系统
- 自建命令知识库
- 易语言代码问答助手

## 关键词

`易语言` `精易模块` `OpenClaw` `Skills` `RAG` `代码生成` `知识库`


path: manifest.yaml
content: name: jingyi-module
slug: jingyi-module
version: 0.1.0
description: Search 精易模块 commands and generate copyable 易语言 code from official docs.
author: pingfan
homepage: https://ec.ijingyi.com/sub.htm
license: MIT
category: development
tags:
  - e-language
  - jingyi
  - chinese
  - code-generation
  - knowledge-base


path: PROMPT.zh-CN.md
content: # 给大模型调用本 Skill 的标准 Prompt

你是一个专门帮助用户编写 **易语言 + 精易模块** 代码的助手。

你的任务不是凭空猜测命令，而是必须优先依赖 `jingyi-module` skill 提供的检索与文档能力。

## 目标

- 根据用户需求，找到最合适的精易模块命令
- 基于真实命令说明生成 **可直接复制运行** 的易语言代码
- 不编造命令名、参数、返回值、备注

## 工作流程

1. 先用 `jingyi-module` skill 搜索最相关命令
2. 对排名最高的 1 到 3 个命令抓取完整说明
3. 确认命令签名、参数、返回值后再写代码
4. 优先生成最短可运行版本

## 输出要求

- 默认输出中文说明
- 代码必须是 **易语言可直接复制格式**
- 代码块优先使用：

```text
.版本 2
...
```

- 如果用户明确要求精易模块实现，就不要改用别的库
- 如果有多个命令可选，要先点明最终采用哪个命令
- 如果命令存在不确定点，只允许用一句短说明交代假设

## 禁止事项

- 不要凭空编造精易模块不存在的命令
- 不要省略关键参数
- 不要把别的语言伪装成易语言
- 不要输出 IDE 操作步骤替代代码
- 不要让用户自己再去查文档

## 回答模板

先用一小段话说明：

- 使用了哪个精易模块命令
- 这个命令为什么适合当前需求

然后直接给一段代码：

```text
.版本 2
...
```

## 检索策略

当用户需求比较模糊时：

- 先按功能词搜索
- 再按命令名搜索
- 再按分类路径搜索

例如：

- “随机汉字” -> `文本_取随机汉字`
- “字体对话框” -> `选择字体`
- “月末日期” -> `时间_取月末`

## 最终原则

宁可少写一句解释，也不要写错命令。

宁可先检索再生成，也不要凭经验硬猜。


path: PUBLISH.zh-CN.md
content: # 上架 ClawHub 步骤

## 1. 准备

- 确保目录里至少有：
  - `SKILL.md`
  - `manifest.yaml`
  - `README.md`
- 本技能已经包含：
  - 检索索引 `data/command_index.jsonl`
  - 搜索脚本 `scripts/search_jingyi.py`
  - 文档抓取脚本 `scripts/fetch_jingyi_doc.py`

## 2. 本地测试

```powershell
python .\scripts\build_command_index.py
python .\scripts\fetch_jingyi_doc.py --name "文本_取随机汉字"
```

## 3. 创建 GitHub 仓库

建议仓库名：

```text
jingyi-module-skill
```

初始化并推送：

```powershell
git init
git add .
git commit -m "init jingyi-module skill"
git branch -M main
git remote add origin 你的仓库地址
git push -u origin main
```

## 4. 安装 ClawHub CLI

```powershell
npm i -g clawhub
```

## 5. 登录

```powershell
clawhub login
```

## 6. 先做 dry-run

```powershell
clawhub publish . --slug jingyi-module --name "Jingyi Module" --version 0.1.0 --tags latest --dry-run
```

## 7. 正式发布

```powershell
clawhub publish . --slug jingyi-module --name "Jingyi Module" --version 0.1.0 --tags latest
```

## 8. 后续更新

版本号递增后重新发布：

```powershell
clawhub publish . --slug jingyi-module --name "Jingyi Module" --version 0.1.1 --tags latest --changelog "improve search and docs fetch"
```

## 9. 用户安装

```powershell
clawhub install jingyi-module
```

或：

```powershell
openclaw skills install jingyi-module
```


path: README.md
content: # jingyi-module skill

An OpenClaw skill for 精易模块 retrieval and 易语言 code generation from official docs.

## 精易模块 OpenClaw 技能

`jingyi-module` 是一个面向 **精易模块 / 易语言** 的 OpenClaw 技能包，专门用于解决“模型知道需求，但不知道该用哪个精易模块命令”这个问题。

它的工作方式不是靠模型硬记命令，而是先检索精易模块命令索引，再抓取对应的官方说明，最后基于真实命令签名生成 **可直接复制运行** 的易语言代码。

这个技能适合这些场景：

- 构建“精易模块问答助手”
- 构建“易语言代码生成助手”
- 训练或增强“易语言大模型”
- 给 RAG / Agent / Skills 系统提供精易模块能力

### 核心能力

- 检索精易模块命令名称、路径与摘要
- 按命令名或命令 id 抓取官方说明
- 对官方空响应命令进行补录兜底
- 生成以 `.版本 2` 开头的可复制易语言代码
- 尽量避免模型编造命令、参数和返回值

### 为什么需要它

精易模块命令很多，直接依赖模型记忆很容易出现：

- 命令名写错
- 参数顺序写错
- 返回值类型搞错
- 把不存在的命令当成精易模块命令

`jingyi-module` 通过“**先检索，再生成**”的方式，把模型回答建立在真实文档之上，让生成结果更稳、更像真正能运行的易语言代码。

### 适合谁

- 想做易语言 AI 助手的开发者
- 想把精易模块接入大模型系统的人
- 想做技能市场、知识库、问答系统的人
- 想让 AI 更准确使用精易模块的易语言用户

## Features

- built-in compact command index (`6856` entries)
- official doc fetch by command id or name
- built-in supplements for the 3 known official empty-response commands
- retrieval-first design for better code generation quality

## Files

- `SKILL.md`: skill instructions
- `manifest.yaml`: package metadata
- `data/command_index.jsonl`: retrieval index
- `scripts/search_jingyi.py`: search commands
- `scripts/fetch_jingyi_doc.py`: fetch docs
- `scripts/build_command_index.py`: rebuild index
- `GITHUB_INTRO.zh-CN.md`: GitHub 中文封面介绍
- `PROMPT.zh-CN.md`: 给大模型调用的标准 prompt
- `PUBLISH.zh-CN.md`: ClawHub 上架说明

## Local build

```powershell
python .\scripts\build_command_index.py
```

## Local test

```powershell
python .\scripts\fetch_jingyi_doc.py --name "文本_取随机汉字"
```

Note:

- On some Windows PowerShell consoles, direct Chinese argv input may be affected by local code page settings.
- The index and scripts are stored as UTF-8.

## Publish

See:

- `PUBLISH.zh-CN.md`
- `GITHUB_INTRO.zh-CN.md`
- `PROMPT.zh-CN.md`

## Install

Typical commands:

```powershell
clawhub install jingyi-module
```

or:

```powershell
openclaw skills install jingyi-module
```


path: scripts/build_command_index.py
content: import json
import pathlib
import re


BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
SOURCE_JSONL = BASE_DIR.parent / "ijingyi_export" / "docs_clean.jsonl"
OUT_DIR = BASE_DIR / "data"
OUT_FILE = OUT_DIR / "command_index.jsonl"

SUPPLEMENT_SUMMARIES = {
    810: ".子程序 时间_取月末, 日期时间型, , 源码由论坛用户【ds9660】雕哥提供。",
    1109: ".子程序 文本_取随机汉字, 文本型, , 取常用的随机汉字",
    6255: ".子程序 选择字体, 字体, , 打开选择字体对话框，成功返回字体相关信息。",
}


def strip_html_summary(text: str) -> str:
    text = re.sub(r"复制命令（简易）|复制命令（带参数说明）|复制声明代码", " ", text)
    text = re.sub(r"子程序名|返回值类型|公开|备\s*注|参数名|类\s*型|参考|可空|数组", " ", text)
    text = re.sub(r"\s+", " ", text).strip()
    if len(text) > 160:
        text = text[:160].rstrip() + "..."
    return text


def split_keywords(text: str):
    parts = re.split(r"[\s_/\-，。；、（）()\[\]【】]+", text)
    return [p for p in parts if p]


def make_summary(item: dict) -> str:
    if item.get("id") in SUPPLEMENT_SUMMARIES:
        return SUPPLEMENT_SUMMARIES[item["id"]]
    text = item.get("content_text", "") or ""
    lines = [line.strip() for line in text.splitlines() if line.strip()]
    if not lines:
        return ""
    preferred = []
    for line in lines:
        if line.startswith(".子程序") or line.startswith(".类") or line.startswith(".DLL命令") or line.startswith(".参数"):
            preferred.append(line)
        if len(preferred) >= 3:
            break
    if preferred:
        return strip_html_summary(" ".join(preferred))
    return strip_html_summary(" ".join(lines[:3]))


def short_name(name: str) -> str:
    if "_" in name:
        return name.split("_", 1)[1]
    return name


def main():
    OUT_DIR.mkdir(parents=True, exist_ok=True)
    count = 0
    with SOURCE_JSONL.open("r", encoding="utf-8") as src, OUT_FILE.open("w", encoding="utf-8") as out:
        for line in src:
            line = line.strip()
            if not line:
                continue
            item = json.loads(line)
            record = {
                "id": item.get("id"),
                "pid": item.get("pid"),
                "name": item.get("canonical_name") or item.get("name") or "",
                "short_name": short_name(item.get("canonical_name") or item.get("name") or ""),
                "canonical_path": item.get("canonical_path") or item.get("tree_path") or "",
                "cmdtype": item.get("cmdtype"),
                "is_dir": item.get("is_dir"),
                "summary": make_summary(item),
                "keywords": sorted(
                    set(
                        split_keywords(item.get("canonical_name") or "")
                        + split_keywords(item.get("canonical_path") or "")
                    )
                ),
            }
            out.write(json.dumps(record, ensure_ascii=False) + "\n")
            count += 1
    print(json.dumps({"written": count, "file": str(OUT_FILE)}, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()


path: scripts/fetch_jingyi_doc.py
content: import argparse
import json
import pathlib
import sys

import requests


BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
INDEX_FILE = BASE_DIR / "data" / "command_index.jsonl"
API_URL = "https://ec.ijingyi.com/plugin.php?id=plugin1&"

SUPPLEMENTS = {
    810: {
        "id": 810,
        "name": "时间_取月末",
        "content_text": ".版本 2\n\n.子程序 时间_取月末, 日期时间型, , 源码由论坛用户【ds9660】雕哥提供。\n.参数 参_指定时间, 日期时间型, 可空 ,",
    },
    1109: {
        "id": 1109,
        "name": "文本_取随机汉字",
        "content_text": ".版本 2\n\n.子程序 文本_取随机汉字, 文本型, , 取常用的随机汉字\n.参数 个数, 整数型, , 要取出多少个汉字！\n.参数 汉字或全拼, 整数型, 可空 , 0为汉字，否则为全拼音！",
    },
    6255: {
        "id": 6255,
        "name": "选择字体",
        "content_text": ".版本 2\n\n.类 类_通用对话框, , 公开 ,\n\n.子程序 选择字体, 字体, , 打开选择字体对话框，成功返回字体相关信息，调用格式如； 编辑框.字体=选择字体()\n.参数 字体名称, 文本型, 可空 ,\n.参数 字体大小, 整数型, 可空 ,\n.参数 字体颜色, 整数型, 可空 ,\n.参数 加粗, 逻辑型, 可空 ,\n.参数 倾斜, 逻辑型, 可空 ,\n.参数 删除线, 逻辑型, 可空 ,\n.参数 下划线, 逻辑型, 可空 ,\n.参数 lRes, 逻辑型, 参考 可空 , 如果用户单击对话框的OK按钮，则返回值为真。",
    },
}


def load_index():
    if not INDEX_FILE.exists():
        raise FileNotFoundError(f"index file not found: {INDEX_FILE}")
    data = []
    with INDEX_FILE.open("r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            data.append(json.loads(line))
    return data


def find_by_name(name: str):
    for item in load_index():
        if item.get("name") == name or item.get("short_name") == name:
            return item
    return None


def fetch_by_id(doc_id: int):
    response = requests.post(
        API_URL,
        data={"mod": "sub", "ac": "getdata", "num": str(doc_id)},
        timeout=20,
        headers={
            "User-Agent": "Mozilla/5.0",
            "X-Requested-With": "XMLHttpRequest",
            "Referer": "https://ec.ijingyi.com/sub.htm",
        },
    )
    response.raise_for_status()
    if not response.text.strip():
        if doc_id in SUPPLEMENTS:
            return {
                "result": 1,
                "data": {
                    "id": doc_id,
                    "name": SUPPLEMENTS[doc_id]["name"],
                    "content_text": SUPPLEMENTS[doc_id]["content_text"],
                    "supplemented": True,
                },
            }
        raise RuntimeError("official API returned empty body")
    data = response.json()
    if not data.get("result"):
        raise RuntimeError(data.get("error") or "API returned failure")
    return data


def main():
    parser = argparse.ArgumentParser(description="Fetch 精易模块 command docs")
    parser.add_argument("--id", type=int, help="fetch by command id")
    parser.add_argument("--name", help="fetch by command name")
    args = parser.parse_args()

    doc_id = args.id
    if doc_id is None:
        if not args.name:
            print("must provide --id or --name", file=sys.stderr)
            sys.exit(1)
        try:
            item = find_by_name(args.name)
        except Exception as exc:
            print(str(exc), file=sys.stderr)
            sys.exit(1)
        if not item:
            print("command name not found", file=sys.stderr)
            sys.exit(1)
        doc_id = int(item["id"])

    try:
        data = fetch_by_id(doc_id)
    except Exception as exc:
        print(json.dumps({"error": str(exc), "id": doc_id}, ensure_ascii=False, indent=2))
        sys.exit(1)

    print(json.dumps(data, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()


path: scripts/search_jingyi.py
content: import argparse
import json
import pathlib
import re
import sys


BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
INDEX_FILE = BASE_DIR / "data" / "command_index.jsonl"


def tokenize(text: str):
    parts = re.split(r"[\s_/\-，。；、（）()\[\]【】]+", text.lower())
    return [p for p in parts if p]


def load_index():
    if not INDEX_FILE.exists():
        raise FileNotFoundError(f"index file not found: {INDEX_FILE}")
    items = []
    with INDEX_FILE.open("r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            items.append(json.loads(line))
    return items


def score_item(query: str, item: dict) -> int:
    q = query.lower().strip()
    score = 0
    name = item.get("name", "").lower()
    short_name = item.get("short_name", "").lower()
    path = item.get("canonical_path", "").lower()
    summary = item.get("summary", "").lower()
    keywords = " ".join(item.get("keywords", [])).lower()

    if q == name:
        score += 200
    if q == short_name and short_name:
        score += 180
    if q in name:
        score += 120
    if q in short_name and short_name:
        score += 100
    if q in path:
        score += 80
    if q in summary:
        score += 40
    if q in keywords:
        score += 30

    for token in tokenize(q):
        if token in name:
            score += 35
        if token in short_name and short_name:
            score += 28
        if token in path:
            score += 20
        if token in summary:
            score += 8
        if token in keywords:
            score += 12

    return score


def main():
    parser = argparse.ArgumentParser(description="Search 精易模块 command index")
    parser.add_argument("query", help="search keyword")
    parser.add_argument("--top", type=int, default=8)
    args = parser.parse_args()

    try:
        items = load_index()
    except Exception as exc:
        print(json.dumps({"error": str(exc)}, ensure_ascii=False, indent=2))
        sys.exit(1)

    ranked = []
    for item in items:
        score = score_item(args.query, item)
        if score > 0:
            ranked.append((score, item))

    ranked.sort(
        key=lambda x: (
            -x[0],
            len(x[1].get("short_name", "") or x[1].get("name", "")),
            x[1].get("id", 0),
        )
    )
    result = []
    for score, item in ranked[: args.top]:
        result.append(
            {
                "id": item.get("id"),
                "name": item.get("name"),
                "short_name": item.get("short_name"),
                "canonical_path": item.get("canonical_path"),
                "cmdtype": item.get("cmdtype"),
                "score": score,
                "summary": item.get("summary", ""),
            }
        )

    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)