npx skills add https://github.com/avifenesh/awesome-slash --skill sync-docs统一技能,用于将文档与代码状态同步。将发现、分析和 CHANGELOG 更新结合到单一工作流中。
const args = '$ARGUMENTS'.split(' ').filter(Boolean);
const mode = args.find(a => ['report', 'apply'].includes(a)) || 'report';
const scope = args.find(a => a.startsWith('--scope='))?.split('=')[1] || 'recent';
const includeUndocumented = args.includes('--include-undocumented');
步骤 1 : 获取已更改的文件(使用 Bash):
# 近期更改(默认范围)
git diff --name-only origin/main..HEAD 2>/dev/null || git diff --name-only HEAD~5..HEAD
# 或者获取所有文件
git ls-files '*.md'
步骤 2 : 查找引用已更改文件的文档(使用 Grep):
*.md 文件中搜索文件名、函数名、类名步骤 3 : 分析每个文档的问题:
: 检查 CHANGELOG:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
## [Unreleased] 部分步骤 5 : 如果存在仓库映射({stateDir}/repo-map.json - 平台状态目录):
undocumented-export 问题参数:[report|apply] [--scope=all|recent|before-pr] [--include-undocumented]
report(默认)或 applyrecent(默认):自上次提交到 main 分支以来更改的文件all:扫描所有文档与所有代码before-pr:当前分支中的文件,为 /next-task 第 11 阶段优化此技能编排所有文档同步操作:
sync-docs skill
|-- Phase 1: Detect project context
|-- Phase 2: Find related docs (lib/collectors/docs-patterns)
|-- Phase 3: Analyze issues
|-- Phase 3.5: Find undocumented exports (repo-map integration)
|-- Phase 4: Check CHANGELOG
|-- Phase 5: Return structured results
该技能不得直接应用修复。它返回结构化数据,供编排器决定如何处理。
以下部分描述了内部的 JavaScript 实现,仅供参考。智能体应使用 Bash、Read 和 Grep 工具遵循上述快速开始指令。
检测项目类型并查找文档文件。
在分析问题之前,确保仓库映射可用以进行准确的符号检测:
const { ensureRepoMap } = require('../../lib/collectors/docs-patterns');
// 尝试获取 repo-map(如果 ast-grep 可用,将自动初始化)
const repoMapStatus = await ensureRepoMap({
cwd: process.cwd(),
askUser: async (opts) => {
// 使用 AskUserQuestion 工具
const answer = await AskUserQuestion({
question: opts.question,
header: opts.header,
options: opts.options
});
return answer;
}
});
if (repoMapStatus.installInstructions) {
// 用户想要安装 ast-grep,显示说明
console.log(repoMapStatus.installInstructions);
// 等待用户确认安装,然后重试
}
// repoMapStatus.available 指示是否可以使用 repo-map
// repoMapStatus.fallbackReason 解释不可用的原因
用户交互(仅在 ast-grep 未安装时):
使用 AskUserQuestion:
如果用户拒绝或仓库映射不可用,系统将自动回退到基于正则表达式的导出检测。
const fs = require('fs');
const path = require('path');
const glob = require('glob');
// 检测文档文件
const docFiles = [];
const commonDocs = ['README.md', 'CHANGELOG.md', 'CONTRIBUTING.md', 'docs/**/*.md'];
for (const pattern of commonDocs) {
// 使用 glob 查找匹配的文件
const matches = glob.sync(pattern, { cwd: process.cwd() });
docFiles.push(...matches);
}
// 从 package.json、Cargo.toml、go.mod 等检测项目类型
let projectType = 'unknown';
if (fs.existsSync('package.json')) projectType = 'javascript';
else if (fs.existsSync('Cargo.toml')) projectType = 'rust';
else if (fs.existsSync('go.mod')) projectType = 'go';
else if (fs.existsSync('pyproject.toml') || fs.existsSync('setup.py')) projectType = 'python';
const context = { docFiles, projectType };
此阶段收集项目上下文,无需外部脚本。
使用 lib/collectors/docs-patterns 查找与已更改文件相关的文档:
// 使用从技能目录到插件 lib 的相对路径
// 路径:skills/sync-docs/ -> ../../lib
const { collectors } = require('../../lib');
const docsPatterns = collectors.docsPatterns;
// 根据范围获取已更改的文件
let changedFiles;
if (scope === 'all') {
changedFiles = await exec("git ls-files '*.js' '*.ts' '*.py' '*.go' '*.rs' '*.java'");
} else if (scope === 'before-pr') {
changedFiles = await exec("git diff --name-only origin/main..HEAD");
} else {
// recent(默认):获取默认分支名称
let base = 'main';
try {
const { stdout: refOutput } = await exec("git symbolic-ref refs/remotes/origin/HEAD");
// 解析 "refs/remotes/origin/branch-name" 以提取 "branch-name"
const rawBase = refOutput.trim().split('/').pop();
// 清理分支名称以防止 shell 注入(仅允许字母数字、短横线、下划线、点)
if (/^[a-zA-Z0-9._-]+$/.test(rawBase)) {
base = rawBase;
}
} catch (e) {
base = 'main'; // 如果 symbolic-ref 失败,回退到 main
}
changedFiles = await exec(`git diff --name-only origin/${base}..HEAD 2>/dev/null || git diff --name-only HEAD~5..HEAD`);
}
// 查找相关文档
const relatedDocs = docsPatterns.findRelatedDocs(changedFiles.split('\n').filter(Boolean), {
cwd: process.cwd()
});
对于每个相关文档,检查问题:
const allIssues = [];
for (const { doc, referencedFile } of relatedDocs) {
const issues = docsPatterns.analyzeDocIssues(doc, referencedFile, {
cwd: process.cwd()
});
issues.forEach(issue => {
allIssues.push({
...issue,
doc,
referencedFile
});
});
}
检测到的问题类型:
outdated-version:版本字符串与当前版本不匹配removed-export:引用了已移除的符号code-example:代码示例可能已过时import-path:导入路径已更改undocumented-export:代码中存在导出项,但任何文档均未提及(需要 repo-map)const changelogResult = docsPatterns.checkChangelog(changedFiles.split('\n').filter(Boolean), {
cwd: process.cwd()
});
// changelogResult 包含:
// - exists: boolean
// - hasUnreleased: boolean
// - documented: string[]
// - undocumented: string[]
// - suggestion: string | null
将所有结果合并为单个输出:
{
"mode": "report|apply",
"scope": "recent|all|before-pr|path",
"context": {
"projectType": "javascript|python|rust|go|unknown",
"docFiles": ["README.md", "CHANGELOG.md"]
},
"repoMap": {
"available": true,
"fallbackReason": null,
"stats": { "files": 142, "symbols": 847 }
},
"discovery": {
"changedFilesCount": 5,
"relatedDocsCount": 3,
"relatedDocs": [
{ "doc": "README.md", "referencedFile": "src/api.js", "referenceTypes": ["filename", "import"] }
]
},
"issues": [
{
"type": "outdated-version",
"severity": "low",
"doc": "README.md",
"line": 15,
"current": "1.0.0",
"expected": "1.1.0",
"autoFix": true,
"suggestion": "Update version from 1.0.0 to 1.1.0"
}
],
"undocumentedExports": [
{
"type": "undocumented-export",
"severity": "low",
"file": "src/utils.js",
"name": "formatDate",
"line": 25,
"certainty": "MEDIUM",
"suggestion": "Export 'formatDate' in src/utils.js is not mentioned in any documentation"
}
],
"fixes": [
{
"file": "README.md",
"type": "update-version",
"line": 15,
"search": "1.0.0",
"replace": "1.1.0"
}
],
"changelog": {
"exists": true,
"hasUnreleased": true,
"undocumented": ["feat: add new feature"],
"status": "needs-update|ok"
},
"summary": {
"issueCount": 3,
"fixableCount": 2,
"bySeverity": { "high": 0, "medium": 1, "low": 2 }
}
}
在标记之间输出 JSON 结果:
=== SYNC_DOCS_RESULT ===
{JSON output}
=== END_RESULT ===
Skill: sync-docs
Args: report --scope=recent
Skill: sync-docs
Args: apply --scope=before-pr
编排器接收结构化结果,并在需要修复时生成 simple-fixer。
每周安装次数
1
仓库
GitHub 星标数
550
首次出现
1 天前
安全审计
安装于
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1
Unified skill for syncing documentation with code state. Combines discovery, analysis, and CHANGELOG update into a single workflow.
const args = '$ARGUMENTS'.split(' ').filter(Boolean);
const mode = args.find(a => ['report', 'apply'].includes(a)) || 'report';
const scope = args.find(a => a.startsWith('--scope='))?.split('=')[1] || 'recent';
const includeUndocumented = args.includes('--include-undocumented');
Step 1 : Get changed files (use Bash):
# Recent changes (default scope)
git diff --name-only origin/main..HEAD 2>/dev/null || git diff --name-only HEAD~5..HEAD
# Or for all files
git ls-files '*.md'
Step 2 : Find docs that reference changed files (use Grep):
*.md filesStep 3 : Analyze each doc for issues:
Step 4 : Check CHANGELOG:
## [Unreleased] sectionStep 5 : If repo-map exists ({stateDir}/repo-map.json - platform state directory):
undocumented-export issuesArguments: [report|apply] [--scope=all|recent|before-pr] [--include-undocumented]
report (default) or applyrecent (default): Files changed since last commit to mainall: Scan all docs against all codebefore-pr: Files in current branch, optimized for /next-task Phase 11This skill orchestrates all documentation sync operations:
sync-docs skill
|-- Phase 1: Detect project context
|-- Phase 2: Find related docs (lib/collectors/docs-patterns)
|-- Phase 3: Analyze issues
|-- Phase 3.5: Find undocumented exports (repo-map integration)
|-- Phase 4: Check CHANGELOG
|-- Phase 5: Return structured results
The skill MUST NOT apply fixes directly. It returns structured data for the orchestrator to decide what to do.
The sections below describe the internal JavaScript implementation for reference only. Agents should follow the Quick Start instructions above using Bash, Read, and Grep tools.
Detect project type and find documentation files.
Before analyzing issues, ensure repo-map is available for accurate symbol detection:
const { ensureRepoMap } = require('../../lib/collectors/docs-patterns');
// Try to get repo-map (will auto-init if ast-grep available)
const repoMapStatus = await ensureRepoMap({
cwd: process.cwd(),
askUser: async (opts) => {
// Use AskUserQuestion tool
const answer = await AskUserQuestion({
question: opts.question,
header: opts.header,
options: opts.options
});
return answer;
}
});
if (repoMapStatus.installInstructions) {
// User wants to install ast-grep, show instructions
console.log(repoMapStatus.installInstructions);
// Wait for user to confirm installation, then retry
}
// repoMapStatus.available indicates if repo-map can be used
// repoMapStatus.fallbackReason explains why if not available
User Interaction (only if ast-grep not installed):
Use AskUserQuestion:
If user declines or repo-map unavailable, the system falls back to regex-based export detection automatically.
const fs = require('fs');
const path = require('path');
const glob = require('glob');
// Detect documentation files
const docFiles = [];
const commonDocs = ['README.md', 'CHANGELOG.md', 'CONTRIBUTING.md', 'docs/**/*.md'];
for (const pattern of commonDocs) {
// Use glob to find matching files
const matches = glob.sync(pattern, { cwd: process.cwd() });
docFiles.push(...matches);
}
// Detect project type from package.json, Cargo.toml, go.mod, etc.
let projectType = 'unknown';
if (fs.existsSync('package.json')) projectType = 'javascript';
else if (fs.existsSync('Cargo.toml')) projectType = 'rust';
else if (fs.existsSync('go.mod')) projectType = 'go';
else if (fs.existsSync('pyproject.toml') || fs.existsSync('setup.py')) projectType = 'python';
const context = { docFiles, projectType };
This phase gathers context about the project without requiring external scripts.
Use lib/collectors/docs-patterns to find docs related to changed files:
// Use relative path from skill directory to plugin lib
// Path: skills/sync-docs/ -> ../../lib
const { collectors } = require('../../lib');
const docsPatterns = collectors.docsPatterns;
// Get changed files based on scope
let changedFiles;
if (scope === 'all') {
changedFiles = await exec("git ls-files '*.js' '*.ts' '*.py' '*.go' '*.rs' '*.java'");
} else if (scope === 'before-pr') {
changedFiles = await exec("git diff --name-only origin/main..HEAD");
} else {
// recent (default): get the default branch name
let base = 'main';
try {
const { stdout: refOutput } = await exec("git symbolic-ref refs/remotes/origin/HEAD");
// Parse "refs/remotes/origin/branch-name" to extract "branch-name"
const rawBase = refOutput.trim().split('/').pop();
// Sanitize branch name to prevent shell injection (only allow alphanumeric, dash, underscore, dot)
if (/^[a-zA-Z0-9._-]+$/.test(rawBase)) {
base = rawBase;
}
} catch (e) {
base = 'main'; // fallback to main if symbolic-ref fails
}
changedFiles = await exec(`git diff --name-only origin/${base}..HEAD 2>/dev/null || git diff --name-only HEAD~5..HEAD`);
}
// Find related docs
const relatedDocs = docsPatterns.findRelatedDocs(changedFiles.split('\n').filter(Boolean), {
cwd: process.cwd()
});
For each related doc, check for issues:
const allIssues = [];
for (const { doc, referencedFile } of relatedDocs) {
const issues = docsPatterns.analyzeDocIssues(doc, referencedFile, {
cwd: process.cwd()
});
issues.forEach(issue => {
allIssues.push({
...issue,
doc,
referencedFile
});
});
}
Issue types detected:
outdated-version: Version string doesn't match currentremoved-export: References removed symbolcode-example: Code example may be outdatedimport-path: Import path changedundocumented-export: Export exists in code but not mentioned in any docs (requires repo-map)const changelogResult = docsPatterns.checkChangelog(changedFiles.split('\n').filter(Boolean), {
cwd: process.cwd()
});
// changelogResult contains:
// - exists: boolean
// - hasUnreleased: boolean
// - documented: string[]
// - undocumented: string[]
// - suggestion: string | null
Combine all results into a single output:
{
"mode": "report|apply",
"scope": "recent|all|before-pr|path",
"context": {
"projectType": "javascript|python|rust|go|unknown",
"docFiles": ["README.md", "CHANGELOG.md"]
},
"repoMap": {
"available": true,
"fallbackReason": null,
"stats": { "files": 142, "symbols": 847 }
},
"discovery": {
"changedFilesCount": 5,
"relatedDocsCount": 3,
"relatedDocs": [
{ "doc": "README.md", "referencedFile": "src/api.js", "referenceTypes": ["filename", "import"] }
]
},
"issues": [
{
"type": "outdated-version",
"severity": "low",
"doc": "README.md",
"line": 15,
"current": "1.0.0",
"expected": "1.1.0",
"autoFix": true,
"suggestion": "Update version from 1.0.0 to 1.1.0"
}
],
"undocumentedExports": [
{
"type": "undocumented-export",
"severity": "low",
"file": "src/utils.js",
"name": "formatDate",
"line": 25,
"certainty": "MEDIUM",
"suggestion": "Export 'formatDate' in src/utils.js is not mentioned in any documentation"
}
],
"fixes": [
{
"file": "README.md",
"type": "update-version",
"line": 15,
"search": "1.0.0",
"replace": "1.1.0"
}
],
"changelog": {
"exists": true,
"hasUnreleased": true,
"undocumented": ["feat: add new feature"],
"status": "needs-update|ok"
},
"summary": {
"issueCount": 3,
"fixableCount": 2,
"bySeverity": { "high": 0, "medium": 1, "low": 2 }
}
}
Output the result as JSON between markers:
=== SYNC_DOCS_RESULT ===
{JSON output}
=== END_RESULT ===
Skill: sync-docs
Args: report --scope=recent
Skill: sync-docs
Args: apply --scope=before-pr
The orchestrator receives the structured result and spawns simple-fixer if fixes are needed.
Weekly Installs
1
Repository
GitHub Stars
550
First Seen
1 day ago
Security Audits
Gen Agent Trust HubPassSocketFailSnykPass
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1
Azure Data Explorer (Kusto) 查询技能:KQL数据分析、日志遥测与时间序列处理
114,200 周安装