dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
为 C/C++(含 Qt)源码生成与维护 Doxygen 注释的工作流:文件头、函数、模块分组、行尾与简短注释,并扫描出签名指纹已过期、需要更新的注释。运行时需要 Python 3.10+ 并 `pip install tree-sitter tree-sitter-cpp`。
English | 中文说明
An agent skill for generating and maintaining Doxygen comments in C/C++ (including Qt) sources. It is not a snippet collection but a pipeline an AI coding assistant can drive end to end: read the function signature → generate or complete the comment → mark the comment stale when the code changes.
parse_function.py parses C/C++ signatures withtree-sitter and prints JSON (function name, return type, parameters and their direction, start line, signature fingerprint, optional body snippet). Read-only, no side effects.
/**< */ / short@brief, matching the editor snippet prefixes doxygen_source, doxygen_fun, doxygen_module_head, doxygen_module_end, doxygen_rear, doxygen_nom.
fields are added and the fingerprint is refreshed; existing wording and line order are kept. A file that already carries an @file block is skipped.
@doxygen_sig_fp ; --scancompares the current signature against it and marks "signature changed, comment outdated" functions as stale, which is what makes repository-wide upkeep possible. Pure formatting changes (whitespace, */& placement) do not change the fingerprint.
--write applies it while preserving thetarget file's CRLF/LF style and its UTF-8 / UTF-8-BOM / GBK encoding.
tree-sitter atregistration and puts the verdict at the top of the skill body; on a missing or broken interpreter the skill instructs the agent to stop and hand over the install steps instead of letting a shell error turn into a fake "function not found". node scripts/check_env.mjs runs the same probe on demand — it is plain Node, so it works where Python does not.
would otherwise cause.
doxygen-comment/
├── SKILL.md # skill body: workflow, script contract, template list
├── README.md # this file
├── LICENSE # MIT
├── requirements.txt # Python dependencies
├── package.json # DSH plugin manifest — declares dsh.bundle
├── cordis.patch.yml # plugin insert row (id: doxygen-comment, name: dsh-doxygen)
├── index.js # registers the bundled skill when installed as a plugin
├── assets/
│ └── cpp.json # the six templates as editor snippets (optional)
├── references/
│ └── examples.md # before/after examples, Qt cases, common mistakes
└── scripts/
├── parse_function.py # read: locate a function + parse its signature (no side effects)
├── gen_doxygen.py # write: render / insert / complete / fingerprint / diff / scan
├── install_snippets.py # optional: merge the snippets into a VS Code style IDE
├── check_env.mjs # environment preflight (Node, works without Python)
└── lib/
└── env.mjs # the probe behind check_env.mjs; also used by index.jsgit clone https://github.com/FantastyQAQ/dsh-doxygen.gitThe repository is named dsh-doxygen while the skill is named doxygen-comment: when you drop it into a skills directory, name the directory `doxygen-comment`.
Two ways in — as a DSH plugin bundle, or by copying the folder into a skills directory.
As a DSH plugin. The repository root declares dsh.bundle, so it installs like any other plugin:
dsh plugin --profile desktop add github:FantastyQAQ/dsh-doxygendesktop is the profile the desktop app uses — swap in your own profile name (desktop+office, etc.). The --profile flag is required by current hosts (0.2.1 and newer); dsh plugin add ... alone fails with required option '--profile ' not specified.
index.js registers SKILL.md as the doxygen-comment skill and resolves ${SKILL_DIR} for you, so no path guessing is needed.
By copying the folder. The directory is self-contained; the scripts contain no project-specific paths:
Host · Skills directory DeepSeek Harness · ~/.dsh/skills/doxygen-comment/ Claude Code · ~/.claude/skills/doxygen-comment/, or a project's .claude/skills/ CodeBuddy CN / WorkBuddy · ~/.codebuddy/skills/doxygen-comment/, ~/.workbuddy/skills/doxygen-comment/
# e.g. install for Claude Code at user level
git clone https://github.com/FantastyQAQ/dsh-doxygen.git "$env:USERPROFILE\.claude\skills\doxygen-comment"Requires Python 3.10+; install the C/C++ parser with pip install tree-sitter tree-sitter-cpp:
pip install tree-sitter tree-sitter-cpp
# or the version-constrained install from this repo:
pip install -r requirements.txtTested with tree-sitter 0.26.0 + tree-sitter-cpp 0.23.4; the scripts support the Language/Parser construction API both before and after 0.22. On Windows, always type python (python3 is an alias trap in some environments).
When Python is missing, the plugin says so instead of failing mid-command. The bundle probes the machine once when it registers the skill and puts the verdict at the top of the skill body; a failing verdict tells the agent to stop and hand the install steps to you. The probe is plain Node (Node ships with DSH), so it can report "no Python" on the very machines where no Python exists:
node scripts/check_env.mjs # human readable, exit 0/2/3
node scripts/check_env.mjs --json # machine readableExit codes: 0 usable, 2 no Python at all, 3 Python found but unusable (too old, modules missing, interpreter broken). If Python is installed but not on PATH (venv, conda, portable build), set DOXYGEN_PYTHON to the interpreter's absolute path and restart the session.
node scripts/check_env.mjs # environment: Python + tree-sitter
python scripts/parse_function.py --file demo.cpp --listIf the first prints ✅ and the second prints an array of functions, the installation works.
The commands below are run from the skill root; replace : with your source path.
python scripts/parse_function.py --file src/rtc.cpp --line 42 --body-lines 30
python scripts/parse_function.py --file src/rtc.cpp --name RTC_Init
python scripts/parse_function.py --file src/rtc.cpp --list # list all (no body_snippet)The output is UTF-8 JSON:
{
"name": "RTC_Init",
"return_type": "int32_t",
"params": [
{"type": "const RTC_Config_t*", "name": "config", "direction": "in"},
{"type": "uint32_t*", "name": "status", "direction": "out"}
],
"start_line": 42,
"end_line": 68,
"is_definition": true,
"signature": "int32_t RTC_Init(const RTC_Config_t* config, uint32_t* status)",
"fingerprint": "ac50cb812857de87",
"file": "…/rtc.cpp"
}direction is decided by the script using the parameter-direction rules (the "参数方向判断规则" section of SKILL.md); take it as given.
Hand the signature plus the body snippet from the previous step to the model and let it produce the description JSON:
{
"brief": "初始化 RTC 外设",
"params": [
{"name": "config", "desc": "RTC 配置参数"},
{"name": "status", "desc": "初始化状态码,非 0 表示失败"}
],
"return_desc": "0 成功,非 0 为错误码",
"retval": "none",
"details": "调用前需保证 32.768kHz 晶振已起振。"
}Then render, preview and apply:
python scripts/gen_doxygen.py --file src/rtc.cpp --line 42 --kind fun --doc doc.json --diff
python scripts/gen_doxygen.py --file src/rtc.cpp --line 42 --kind fun --doc doc.json --writeWithout --diff/--write it prints JSON (with status, notes, changed, diff fields).
# file header (inserted at the first line of the file)
python scripts/gen_doxygen.py --file src/rtc.cpp --kind source \
--brief "RTC 驱动" --note "依赖 32.768kHz 晶振" --log-desc "创建" --diff
# module group head / tail (used as a pair)
python scripts/gen_doxygen.py --file src/rtc.cpp --kind module --line 30 \
--group rtc_api --title "RTC API" --brief "RTC 对外接口" --desc "全部函数可重入" --diff
python scripts/gen_doxygen.py --file src/rtc.cpp --kind module-end --line 120 --diff
# trailing comment / short comment (no signature parsing needed)
python scripts/gen_doxygen.py --file src/rtc.h --kind rear --line 18 --text "已发送帧数" --diff
python scripts/gen_doxygen.py --file src/rtc.h --kind nom --line 25 --brief "RTC 状态枚举" --diffpython scripts/gen_doxygen.py --scan srcIt returns {"summary": {...}, "items": [...]} where every function carries a status:
scan status · meaning · what to do missing · no Doxygen block above it · add one with the function-comment flow stale · block exists but the fingerprint no longer matches (the code changed) · review the description, then refresh partial · block exists but fields are missing (e.g. no @param) · fill in only what is missing ok · complete and fingerprint matches · leave it alone
The scan skips .git, build, libs, node_modules and similar directories. Do not rewrite hundreds of files in one go: group by status and let the user pick the scope first.
Script · Purpose parse_function.py --file --line/--name/--list [--body-lines N] · parse a signature gen_doxygen.py --file … --kind · generate one comment gen_doxygen.py --scan · scan comment status across a tree
Both scripts share the same exit codes:
Code · Meaning 0 · Success (including status=ok/skipped, i.e. "nothing to change") 1 · Target function not found / not enough arguments 2 · Argument or file error (missing path, invalid JSON) 3 · The tree-sitter dependency is missing
On failure the reason is written to stderr, and stdout never carries a half-written JSON document.
The author and copyright in file headers have no universal default: when nothing is specified the script writes the placeholders ` and Copyright (c) by , All Rights Reserved.` for the user to replace. There are two ways to specify them:
python scripts/gen_doxygen.py --file a.cpp --kind source --brief "…" \
--author "Your Name (you@example.com)" --copyright "Copyright (c) 2026 by Your Company, All Rights Reserved."# set once, then every later command reuses it
export DOXYGEN_AUTHOR="Your Name (you@example.com)"
export DOXYGEN_COPYRIGHT="Copyright (c) {year} by Your Company, All Rights Reserved." # {year} becomes the current yearassets/cpp.json is exactly the six templates as editor snippets. Type doxygen_fun and press Tab to expand it:
python scripts/install_snippets.py # dry run: detect IDEs, show what would be merged (writes nothing)
python scripts/install_snippets.py --apply --create # actually write
python scripts/install_snippets.py --uninstall --apply # remove the snippets this skill installed\snippets\cpp.json; it is merged, never overwritten, and theprevious file is backed up as cpp.json.bak-.
cpp.json only applies to .cpp/.cc/.cxx; to use them in .c/.hyou must merge them into c.json in the same directory.
settings.json is left alone.--target