mcpField
D
dx-apexguru-scan

dx-apexguru-scan

github.com/forcedotcomテスト・品質1.1k2.7k 回インストール1 日前に更新
リポジトリ

dx-apexguru-scan について

Salesforce Apex プロジェクト向けのスキルです。ApexGuru SFAP Scan API で性能上のアンチパターンを検査し、違反と修正案をレポートにまとめます。

主な機能

  1. 01プロジェクト内の Apex ファイルをパッケージ化
  2. 02スキャンの送信と状態のポーリング
  3. 03違反レポートのデコードと表示
  4. 04既存結果をルールで絞り込み

活用シーン

  1. 01SOQL や DML のループ内実行を確認
  2. 02WHERE または LIMIT のない SOQL を検出
  3. 03重大度でスキャン結果を絞り込み

インストール

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

$npx skills add https://github.com/forcedotcom/sf-skills --skill dx-apexguru-scan

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples/
README.md
sample-decoded-summary.json
sample-full-no-runtime-response.json
sample-succeeded-response.json
references/
api-reference.md
authentication.md
error-handling.md
violation-catalog.md
scripts/
build-zip.sh
decode-report.js
resolve-token.sh
run-scan.sh
scan.sh
validate-token.js

詳細

ApexGuru パフォーマンススキャンスキル

重大:スクリプトの使用は必須です

トークンの解決、ZIP 化、API 呼び出し、レポートのデコードなど、すべての手順で <skill_dir>/scripts/ に含まれるスクリプトを必ず使用してください。例外はありません。

誤り — 絶対に行わないでください:
# WRONG: hand-rolled curl to the API
curl -X POST https://api.salesforce.com/... -F [email protected]

# WRONG: inline base64 + jq to read the report
cat raw.json | jq -r .report | base64 -d | jq '.[]'

# WRONG: reading the raw result file directly (report is a large base64 blob)
Read tool → apexguru-raw-*.json

# WRONG: inline node/python to parse violations
node -e "const r = require('./raw.json'); ..."
正しい方法 — 常にこのようにしてください:
# PREFERRED — one command runs all three steps (package → submit+poll →
# decode+present) and prints the ready-to-show report as its final stdout.
# Use this for every initial scan: it cannot be left half-finished.
bash "<skill_dir>/scripts/scan.sh" "<project-root>"

# Optionally persist the presented markdown to a file as well:
bash "<skill_dir>/scripts/scan.sh" "<project-root>" --out ./apexguru-report.md

基盤となる3つのスクリプトは引き続き利用でき、scan.sh が順番に呼び出します。 個別に実行するのは、すでにスキャン済みの結果を詳しく調べる場合(ステップ5)、または中間生成物を意図的に確認する必要がある場合に限ります。

# Equivalent manual chain (scan.sh runs exactly these, in this order):
bash "<skill_dir>/scripts/build-zip.sh" "<project-root>" "./apexguru-<TS>.zip"
bash "<skill_dir>/scripts/run-scan.sh"  "./apexguru-<TS>.zip" "./apexguru-raw-<TS>.json"
node "<skill_dir>/scripts/decode-report.js" "./apexguru-raw-<TS>.json" --present

# Drill into a subset WITHOUT re-scanning (reuse the raw file scan.sh left, or
# pass --raw to scan.sh to keep it at a known path):
node "<skill_dir>/scripts/decode-report.js" "./apexguru-raw-<TS>.json" --rule SOQL_IN_LOOP --full
node "<skill_dir>/scripts/decode-report.js" "./apexguru-raw-<TS>.json" --group file --top 5

<skill_dir> は、この SKILL.md を含むディレクトリの絶対パスです。 絶対に ./scripts/ を使用しないでください。これはスキルのディレクトリではなく、ユーザーの CWD を基準に解決されます。

フィルター、ランク付け、グループ化に関する質問(「問題が最も多いファイルはどれですか?」「SOQL-in-loop のみを表示」「重大度別に分類」など)には、同じ生の結果ファイルを指定してフラグ付きで decode-report.js を再実行し、回答してください。再スキャンしたり、JSON を手作業で解析したりしてはいけません。


重大:--present の出力は一字一句そのまま提示してください — 要約してはいけません

decode-report.js --present(ステップ4)は、すぐに提示できる最終的な Markdown をすでに生成します。重大度の凡例、違反ごとの詳細カード(メッセージ、コード、修正方法、リソースリンク)、最後のサマリーテーブルが含まれます。この標準出力がそのまま回答です。 出力されたとおりにユーザーに提示してください。より短い表に書き換えたり、問題ごとのカードを省いてサマリーテーブルだけにしたり、「違反について説明して」とユーザーに求められるまでメッセージ、修正方法、リソースを記載しなかったりしてはいけません。要約すると、--present の目的そのものが損なわれます。

帰属情報はすでに標準出力に含まれています。サマリー行には、モードを示す正確な出力(例:「ApexGuru (static analysis) is active. To unlock runtime intelligence…」)が記載されています。独自の帰属説明文を前後に追加してはいけません(「帰属情報:analysisMode: static…」のような記述、組織名の記載、「静的解析のみの検出結果」の言い換えなど)。スクリプトの行が、承認済みの完全な表現です。独自の文言を追加すると、出力が非決定的になり、意図から外れます。

誤り — 絶対に行わないでください:
Top Issues (worst first)
#  Severity   Rule                      Method    Line
1  Major      UsingTheTestMethodKeyword legacy... 136
...
Key Antipatterns Detected:
- SOQL/DML in loops (3 violations)

(メッセージ、コード、修正方法をすべて省いた手作りの要約 — それらを含む違反についても同様です)

Attribution: analysisMode: static — source-only analysis. The scanned org
(ag-skills-org) is not onboarded to ApexGuru's full runtime metrics, so
these are static-only findings.

(レポートの前に、エージェントが作成した帰属情報の行を追加 — スクリプト自身のサマリー行にすでにモードが記載されており、この重複は非決定的で、スクリプトがアクセスできなかった組織名まで記載しています)

正しい方法 — 常にこのようにしてください:

decode-report.js --present の標準出力全体を貼り付けてください。すべての ### Issue N カードと最後の ## Summary テーブルを含め、編集せずに1つの回答で提示します。


概要

ApexGuru は、Apex におけるパフォーマンスのアンチパターン(ループ内の SOQL/DML、 Schema.getGlobalDescribe()、WHERE/LIMIT のない SOQL、未使用の SOQL フィールド)を検出します。 このスキルは ApexGuru SFAP Scan API を呼び出します。ユーザーの Apex(プロジェクトルート以下の すべての .cls/.trigger ファイル。配置場所は問いません)を zip にまとめて送信し、スキャンが 完了するまでポーリングし、base64 エンコードされたレポートをデコードして、違反をルール別に 重大度、file:line、修正案とともに提示します。

帰属情報の表示は必須です。 API は analysisMode を返します。

  • static → ソースのみの分析 → 結果に 「Static only」 と表示します。
  • full → ApexGuru にオンボーディング済みの組織から取得したランタイムメトリクスで拡充 → 結果に 「Production insights」 と表示します。

decode-report.js --present は、この帰属情報をサマリー行とタイトル(「Static only」/「Production insights」)に すでに表示しており、必須の帰属情報表示要件を満たしています。この行を正確な出力として表示してください。 独自の帰属情報に関する文を作成したり、組織名を挙げたりしないでください。ユーザーが full を想定していたのに static になった場合、スクリプトの static モードの行に組織がオンボーディングされていないことがすでに説明されています。 この説明を繰り返すのではなく、その行を参照するよう案内してください(エラー処理を参照)。

対象範囲: プロジェクトの Apex の zip 化、スキャンの送信/ポーリング、違反のデコードと提示、 既存結果のフィルタリング/グループ化、API エラーのトラブルシューティング。

対象外: 一般的な静的解析/セキュリティ/Lint(ApexGuru をエンジンの一つとして列挙する dx-code-analyzer-run を使用してください)、コードへの修正の適用、組織の ApexGuru へのオンボーディング、 SFAP トークンの発行。


前提条件

  • 認証済みの sf CLI 組織(sf org login web ...)。resolve-token.sh は <instanceUrl>/ide/auth を通じてそこから SFAP JWT を取得します。これは通常の IDE セッションでの方法です。代わりに、JWT を直接指定する場合(CI/ヘッドレス)は APEXGURU_SFAP_TOKEN/APEXGURU_SFAP_TOKEN_FILE を設定してください。組織はトークンの tnk claim から特定されます。組織 ID は渡しません。特定の組織を選ぶには --org <alias> を渡してください。 <skill_dir>/references/authentication.md を参照してください。トークンを解決できない場合、 スクリプトはヒント付きの明確なエラーを返します。
  • sf、bash、curl、zip、jq、node が PATH 上にあること(macOS/Linux の開発環境では標準的です)。
  • Apex を含むフォルダー — sfdx プロジェクト、force-app/ サブツリー、または .cls/.trigger ファイルを含む任意のフォルダーを指定できます。build-zip.sh は配置場所にかかわらず その下にあるすべての Apex を収集し、API はアーカイブ全体を検索します。

ワークフロー

ステップ 1:プロジェクトルートを特定する

プロジェクトルートは、その下のどこかにApex を含む任意のフォルダーです (通常は sfdx-project.json と同じ階層にある sfdx プロジェクトのルートですが、force-app/ サブツリーや、.cls ファイルだけを含むフォルダーでもかまいません)。ユーザーがパスを指定した場合は それを使用し、指定がない場合は現在の作業ディレクトリを使用します。build-zip.sh はその下にある すべての .cls/.trigger ファイル(配置場所は問いません)を収集し、該当するファイルが一つもなければ 明確なエラーを返します。

ステップ 2:プロジェクトをパッケージ化する
TS=$(date +%Y%m%d-%H%M%S)
bash "<skill_dir>/scripts/build-zip.sh" "<project-root>" "./apexguru-${TS}.zip"

出力 JSON には zip、bytes、humanSize、apexFileCount、scanRoot が含まれます。スクリプトは 圧縮後 200MB の上限を適用し、超過した場合はすぐにエラーを返します。エラー時(error/hint フィールドがある場合)は、そのヒントを伝えて終了します。

Step 3: 送信してポーリングする
bash "<skill_dir>/scripts/run-scan.sh" "./apexguru-${TS}.zip" "./apexguru-raw-${TS}.json"
  • より高速で低コストの実行を希望する場合は、--fast を追加します(LLM を多用する修正案の生成をスキップします)。
  • エンドポイントはトークンの環境に従います。ベース URL はトークンの tnk クレームから導出されます。prod 組織は api.salesforce.com に接続し、内部の stage/dev 組織は stage./dev.api.salesforce.com に接続します。お客様は prod 組織で認証するため、常に prod に接続され、追加のフラグや設定は不要です。
  • --org <alias> を指定すると、JWT の導出元となる認証済み sf 組織を選択できます(省略すると、CLI のデフォルト組織を使用します)。
  • 進行状況(QUEUED → RUNNING → SUCCEEDED)は stderr に出力されます。スクリプトは約 15 秒ごとにポーリングします。デフォルトの上限は 10 分です(--max-polls、--interval で調整できます)。
  • 成功すると、stdout に 1 行の JSON サマリーが出力され、完全な生データの本文が apexguru-raw-${TS}.json に書き込まれます。失敗すると、stdout は {error, httpStatus, status, hint} となります。hint を伝えてください。ステータスコードの詳細については、<skill_dir>/references/error-handling.md を参照してください。
  • フォアグラウンドでのみ実行してください。 バックグラウンドで実行してはいけません。ポーリングの出力を確認する必要があります。
  • スキャンが SUCCEEDED になっても、まだ完了ではありません。 生の結果は Base64 の塊であり、ユーザーに提示できる回答ではありません。スキャンが成功した時点で停止したり、「完了」と報告したりせず、レポートをデコードして提示するため、必ずステップ 4 に進んでください。ステップ 3 でターンを終えると、ユーザーには読める内容が何も残りません。
Step 4: デコードして提示する
node "<skill_dir>/scripts/decode-report.js" "./apexguru-raw-${TS}.json" --present

提示用にデコードする際は、--present をデフォルトで使用します。これは --full を含み(暗黙の上限なし)、そのまま提示できる Markdown を出力します。内容は、深刻度の凡例(Minor/Major/Critical。analysisMode: full で本番メトリクスに基づいて深刻度が補足される場合は Tip マーカーも表示)、ホットスポット以外のルールに関する違反ごとの ### Issue N カード(メッセージ、現在のコード、推奨される修正、ヘルプドキュメントへのリンク。上限は --top で指定し、デフォルトは 10 件。深刻度の高い順に表示し、上限は見出しに明記)、およびカードの上限にかかわらずすべての違反を一覧表示する最後の ## Summary テーブルです。ExpensiveMethods(full モードでのメソッドごとの CPU ホットスポットランキングであり、行単位のアンチパターンではありません)は、メソッドごとにほぼ同じカードを繰り返すのではなく、独立した「CPU Hotspots」ランキングテーブルにまとめられます。この出力はそのままユーザーに提示してください。すぐに提示し、いったん止まって確認を求めたり、より短いテーブルに再要約したりしてはいけません。

ステップ 5 での詳細確認(既存の結果のフィルタリング/グループ化)では、JSON のみを出力する形式(--present なし)で問題ありません。スクリプトを --present なしで実行する場合は、以下の読み取りルールを参照してください。

禁止事項: スクリプトコードをでっち上げること、./scripts/... のようなパスをそのまま使うこと、Base64 をインラインでデコードすること、report フィールドを jq で処理すること、生ファイルを直接 Read すること。

--present を指定しない場合の decode-report.js 出力の読み方

このコマンドは、1 つの JSON オブジェクトを標準出力に出力します。何かを提示する前に、各フィールドを順に確認してください。一部だけをざっと見て、全体を確認したつもりにならないでください。

  1. 何よりも先に truncated を確認してください。 true の場合、groups は上位 --top(デフォルトは 10)件のルールに、各グループの sample は 3 件に、topViolations は --top 件に制限されています。truncated:true の結果を全体像として提示してはいけません。 同じコマンドに --full を追加して再実行し、その出力を使用してください。ユーザーが簡易的な結果や一部の結果を明示的に求めた場合に限り、これを省略できます。
  2. analysisMode/attribution に基づく帰属を明記してください — static/「静的のみ」または full/「本番環境のインサイト」です。上記の「帰属の明記は必須」に従い、毎回必ず記載してください。
  3. serverViolationBreakdown は、API 内部のルールコード(例:SOQL_IN_LOOP_1HOP、GGD)の集計値です。整合性確認用の合計値(violationCount と合致します)であり、表示名ではありません。これらのコードをユーザーに見せてはいけません。代わりに、人が読める groups[].key の名前(例:SoqlInALoopOneHop、SchemaGetGlobalDescribeNotEfficient)を使用してください。
  4. トップレベルの severityCounts は、すべての違反の重大度の内訳です。概要テーブルにはこれを使用してください。各 groups[] エントリにも、そのルールだけを対象とする独自の severityCounts があります。
  5. 「ルール別の違反」テーブルは groups から作成し、各エントリにつき 1 行を設けてください。key → ルール、count → 件数、severityCounts → 重大度、sample[0](または --full の場合は items[0])→ 例(file:line)とします。
  6. 「主な問題」テーブルは topViolations から作成してください。 これは重大度の高い順に並んでいます。rule、severity、file:line、および fixes が空でなければその最初の項目を修正案として使用してください。fixes が空の場合は、修正案の欄に内容を作り足さず、空欄にしてください。
  7. ユーザーが特定の違反について説明を求めた場合(「これはどういう意味ですか」「なぜフラグが立っていますか」など)、その違反の message(平易な言葉で説明した理由)と resources[0](ヘルプドキュメントの URL)を、どちらもそのまま提示してください。これらはすべての違反オブジェクトに含まれていますが、一覧性を保つため、手順 5/6 の概要テーブルには含めていません。message が空の場合に限り、references/violation-catalog.md を参照してください。
  8. fixes が [] でも問題ではありません。API の suggestions フィールド(修正コード)は、すべてのルールに設定されているわけではありません(特に、1 行で修正できない CPU ランキングの ExpensiveMethods)。「修正方法がありません」とは言わず、修正案の欄を空欄にしてください。
  9. --full を指定すると、各グループには items 配列(そのルールに該当するすべての違反。3 件の sample だけではありません)も含まれます。ユーザーが特定ルールの該当項目すべてを求めている場合(「未使用フィールドの SOQL をすべて見せて」など)は、sample ではなく items を使用してください。
プレゼンテーションテンプレート(フォールバック — --present を使用しない場合のみ)

--present(上記のステップ 4 に従い、デフォルト)は、「未加工の出力を読むための手順」セクションで説明されている、重大度の凡例+問題カード+サマリーテーブルを含む完全な出力をすでにレンダリングします。標準出力をそのまま表示してください。未加工の JSON から手作業でテーブルを作成するのは、--present を実際に使用できない場合(例:Markdown レンダラーのないスクリプト/CI 環境)に限ってください。

<Static only | Production insights> タイトルのプレースホルダーの設定: ラベルは analysisMode だけでなく、attribution フィールドから導き出してください。そこには 3 つの状態がすでに反映されています。

  • 「Production insights」(analysisMode: full かつ ランタイムメトリクスあり)— 本番環境のランタイムメトリクスで情報が補完されています。
  • 「Static only」+analysisMode: full(ランタイムメトリクスなし)— 組織はオンボーディング済みですが、このコードのランタイムデータはまだありません。Scale Center でランタイムレポートを生成してください。
  • 「Static only」+analysisMode: static — ソースコードのみです。本番環境のインサイトを得るには、組織を ApexGuru にオンボーディングしてください。

以下のコードフェンスは、レンダリングされる出力そのものです。実際の値に置き換えて表示してください。上記のガイダンスは出力しないでください。

## ApexGuru Scan Complete — <Static only | Production insights>

**Found X performance violations** across Y files.

| Severity | Count |
|----------|-------|
| Critical (1) | X |
| High (2) | X |
| Moderate (3) | X |

### Violations by Rule
| Rule | Count | Severity | Example |
|------|-------|----------|---------|
| SOQL_IN_LOOP | 15 | High (2) | AccountService.cls:42 |
| DML_IN_LOOP | 8 | Critical (1) | AccountService.cls:60 |
| GGD | 2 | Moderate (3) | Utils.cls:12 |

### Top Issues
| # | Rule | Sev | File:Line | Suggested Fix |
|---|------|-----|-----------|---------------|
| 1 | DML_IN_LOOP | 1 | AccountService.cls:60 | Collect records; DML once after the loop |
| ... up to 10 |

Raw result: `./apexguru-raw-<TS>.json`

結果のサイズに応じて表示を調整してください。0 件なら「パフォーマンスのアンチパターンは見つかりませんでした」、1~10 件なら 1 つのテーブル、11 件以上なら重大度別の件数+ルール別テーブル+上位 10 件を表示します。最後に未加工の結果ファイルのパスを記載してください。独自の追加案内(「再スキャンせずに詳しく調べられます……」、または「ルールで絞り込む/ファイルでグループ化する/違反内容を説明する」といったメニュー)を追加しないでください。--present はスクリプトの「すべて表示」フッターをすでに出力しています。これが承認済みの完全な締めくくりの行であり、独自の文言を加えると出力が非決定的になります。 ルールカタログの詳細:<skill_dir>/references/violation-catalog.md。

ステップ 5:結果を詳しく調べる(再スキャンなし)

同じ未加工ファイルに対して decode-report.js を次のフラグで再実行します。

ユーザーの指定フラグ
「SOQL-in-loop だけを表示して」--rule SOQL_IN_LOOP --full
「重大なものだけ」--severity 1
「AccountService.cls の内容は?」--file AccountService.cls --full
「ファイル別にグループ化して」/「最も問題の多いファイルは?」--group file --top 5
「重大度別に内訳を表示して」--group severity
「すべて表示して」--present(または未加工の JSON を表示するには --full)

制約事項と注意点

項目理由/対処方法
スクリプトは絶対パスの <skill_dir> を使って実行する./scripts/ はスキルのディレクトリではなく、ユーザーの CWD を基準に解決されます
プロジェクトのレイアウトは問いませんAPI はアーカイブ全体を走査して Apex を調べます。build-zip.sh はルート以下のすべての .cls/.trigger を収集するため、force-app/ は不要です
report をインラインでデコードしない大きな base64 blob です。必ず decode-report.js を使用してください
最初のデコードには --present を使用する--full(暗黙の上限なし)を含み、表示用の Markdown をそのままレンダリングします。重大度の凡例、問題ごとのカード、締めくくりのサマリーテーブルが含まれ、参照 MCP ツールの表示密度を再現します
絞り込みのために再スキャンしないステップ 5 では、既存の未加工ファイルを瞬時に再デコードします
Attribution はレンダリング済み--present はモード行(「Static only」/「Production insights」)をすでに出力しています。出力をそのまま表示してください。独自の attribution 文を作成したり、組織名を記載したりしないでください
full が想定されるところで static が返る組織が ApexGuru にオンボーディングされていません。エラーとして扱わず、ユーザーに伝えてください
401/403/404/400トークン/組織の所有権/scanId/zip の問題です。references/error-handling.md を参照してください
フォアグラウンドのみ、ポーリング間隔は約 15 秒バックグラウンドで実行すると進捗が失われます。スキャンには数分かかることがあります
トークンは秘密情報resolve-token.sh はトークンを出力しません。トークンを表示したり、結果ファイルに書き込んだりしないでください
セキュリティ/lint スキャナーではないPMD/ESLint/セキュリティのチェックには dx-code-analyzer-run を使用してください

リファレンスとスクリプト一覧

スクリプト(bash/nodeで、絶対パスの<skill_dir>/を先頭に付けて実行します。Readは使用しないでください):

ファイル使用するタイミング
<skill_dir>/scripts/resolve-token.shSFAP JWTとベースURLの解決(run-scan.shから呼び出されます)
<skill_dir>/scripts/validate-token.jsローカルでのJWT事前チェック(ネットワーク不要):環境変数/スコープ/有効期限(resolve-token.shから呼び出されます)
<skill_dir>/scripts/build-zip.shステップ2 — プロジェクトのApexを集め、サイズをチェックしたzipを作成
<skill_dir>/scripts/run-scan.shステップ3 — 完了まで送信とポーリングを実行
<skill_dir>/scripts/decode-report.jsステップ4~5 — base64レポートをデコードし、違反をグループ化/フィルタリング

リファレンス(必要に応じて参照):

ファイル参照するタイミング
references/authentication.mdSFAP JWTの取得元、環境変数/ファイルの設定
references/api-reference.mdエンドポイントの契約、リクエスト/レスポンスの形式、制限
references/violation-catalog.mdApexGuruルールの意味と一般的な修正方法
references/error-handling.md400/401/403/404、FAILED、タイムアウト、静的解析とフル解析の診断

examples/には、SUCCEEDEDレスポンスのサンプルとデコード済みサマリーのサンプルが含まれています。

コメント