mcpField
S
sync-docs

sync-docs

github.com/agent-sh開発1.0k95 回インストール2 日前に更新
リポジトリ

sync-docs について

sync-docsは、コード変更と関連ドキュメントやCHANGELOGを照合し、問題を報告するスキルです。ドキュメントを保守する開発者向けで、スキャン範囲を選べ、未記載のエクスポートも任意で検出します。修正自体は行いません。

主な機能

  1. 01変更ファイルに関連するドキュメントの特定
  2. 02バージョン、エクスポート、例、インポートパスの確認
  3. 03CHANGELOGの記載状況を確認
  4. 04最近、全体、PR前の変更をスキャン
  5. 05未記載のエクスポートを任意で検出

活用シーン

  1. 01コード変更後のドキュメント監査
  2. 02プルリクエスト前のドキュメント確認
  3. 03古い例や参照の発見
  4. 04最近の変更に関するCHANGELOGの確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/agent-sh/agentsys --skill sync-docs

インストール後、Claude Code で/sync-docsを入力して読み込まれたか確認します。

詳細

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 を使用):

# 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'

手順 2:変更されたファイルを参照しているドキュメントを探します(Grep を使用):

  • *.md ファイルからファイル名、関数名、クラス名を検索します
  • README.md、CHANGELOG.md、docs/*.md を確認します

手順 3:各ドキュメントの問題を分析します:

  • バージョンの不一致(ドキュメントのバージョンと package.json を比較)
  • 削除されたエクスポート(ドキュメントには記載されているものの、コードには存在しないシンボル)
  • 古くなったコード例
  • インポートパスの変更

手順 4:CHANGELOG を確認します:

  • ## [Unreleased] セクションを探します
  • 最近のコミットメッセージと CHANGELOG の項目を比較します

手順 5:repo-map が存在する場合({stateDir}/repo-map.json - プラットフォームの状態ディレクトリ):

  • 正確なエクスポート一覧を取得するために読み込みます
  • ドキュメントに記載されていないエクスポートを探します
  • undocumented-export の問題として報告します

入力

引数:[report|apply] [--scope=all|recent|before-pr] [--include-undocumented]

  • モード:report(デフォルト)または apply
  • スコープ:
    • recent(デフォルト):main への最後のコミット以降に変更されたファイル
    • all:すべてのドキュメントをすべてのコードと照合してスキャンします
    • before-pr:現在のブランチ内のファイル。/next-task Phase 11 向けに最適化されています
  • --include-undocumented:どのドキュメントにも記載されていないエクスポートを探します(repo-map を使用)

アーキテクチャ

このスキルは、すべてのドキュメント同期操作を統括します。

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 のツールを使用してください。

フェーズ 1:プロジェクトのコンテキストを検出する

プロジェクトの種類を検出し、ドキュメントファイルを探します。

フェーズ 1.5:Repo-Map を準備する

問題を分析する前に、正確なシンボル検出のために repo-map が利用可能であることを確認します。

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

ユーザーへの確認(ast-grep がインストールされていない場合のみ):

AskUserQuestion を使用します:

  • ヘッダー:「ast-grep が必要です」
  • 質問:「ast-grep が見つかりませんでした。ドキュメント同期の精度を高めるためにインストールしますか?」
  • 選択肢:
    • 「はい。手順を表示」- プラットフォーム別のインストール手順を表示します
    • 「いいえ。正規表現の代替手段を使う」- 精度の低い正規表現ベースの検出を続行します

ユーザーがインストールを拒否した場合、または repo-map を利用できない場合、システムは自動的に正規表現ベースのエクスポート検出に切り替えます。

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 };

このフェーズでは、外部スクリプトを必要とせずにプロジェクトのコンテキストを収集します。

フェーズ 2:関連するドキュメントを探す

lib/collectors/docs-patterns を使用して、変更されたファイルに関連するドキュメントを探します。

// 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()
});

フェーズ 3:ドキュメントの問題を分析する

関連するドキュメントごとに、問題がないか確認します。

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 が必要)

フェーズ 4:CHANGELOG を確認する

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

フェーズ 5:構造化された結果を返す

すべての結果を単一の出力にまとめます。

{
  "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 ===

エージェントでの使用方法

sync-docs-agent(単独の /sync-docs)
Skill: sync-docs
Args: report --scope=recent
/next-task フェーズ 11
Skill: sync-docs
Args: apply --scope=before-pr

オーケストレーターは構造化された結果を受け取り、修正が必要な場合は simple-fixer を起動します。

制約

  1. デフォルトはレポートモード - apply モードが明示的に指定されない限り、ファイルを変更しません
  2. 構造化された出力 - 常にマーカーで囲んだ JSON を返します
  3. 直接修正しない - 修正手順を返し、対応はオーケストレーターに委ねます
  4. 書式を維持する - 修正案では既存のスタイルを維持します
  5. 安全な変更のみ - 自動修正可能な問題のみ、修正項目に含めます

エラー処理

  • git がない場合:エラー「Git required for change detection」で終了します
  • ドキュメントが見つからない場合:空の docFiles を報告し、README.md の作成を提案します
  • 変更されたファイルがない場合:スコープを「empty」と報告し、--scope=all の使用を提案します

コメント