unified slash menu skill invocation_ja - kkamegawa/vsextensionforcodex GitHub Wiki

組み込みコマンドとスキル呼び出しを Slash メニューへ統合

English

日付: 2026-08-11
追跡: Issue #140
ベースライン: main の 249b2c4
実装: codex/140-unified-slash-menu の 6aee497

背景

目標は ChatGPT app と同じように、組み込みコマンドとローカルで利用可能な Codex スキルを一つのインライン Slash メニューへ表示することです。Worker は既に skills/list でスキルを検出しており、本計画では Extension の表示、構造化された turn の受け渡し、永続的なローカルカタログキャッシュを定義します。

ADR-009 は元の v15 呼び出し設計の記録として残します。ADR-010 は、Extension 側のスキル表示20件上限と揮発キャッシュのみという前提だけを置き換えます。Worker の安全上限、平坦化カタログ、完全な同一性検証、欠損耐性、固定 glyph のアイコンフォールバックは維持します。

プロダクト上の決定事項

  • コンポーザーの index 0 にある / で一つのインライン・非Popup候補リストを開きます。//、途中の Slash、/skill、/skills、$skill は対象外です。
  • 組み込み候補を先に表示し、上限は8件のままです。同じ仮想化 ListBox の後半に Skills を表示し、Worker が安全に受理した異なる (Name, Scope, Path) identity を、Worker の安全上限200件まで全て表示します。
  • スキルを選ぶと独立した削除可能な PendingSkill チップを作り、SetComposerText("") で /... の検索文字列だけを消します。通常のコンポーザーは表示したままです。別のスキルを選ぶと置き換え、polite live region で通知します。
  • 無効、stale、受動的な状態行は表示しますが、キーボード選択の対象外です。キャッシュカタログは cached と明示し、live generation が届くまで選択不可です。
  • Busy または WaitingForApproval 中も選択・置換・削除を許可します。スキルが保留中は Send/steer を無効化し、待つかチップを外すよう案内します。チップを外すと既存の text-only steer を再開できます。
  • Ready 状態ではコンポーザーが空でもスキルだけで turn/start を開始できます。一致する turn/start が成功した後だけチップを消し、更新失敗、stale 検証、送信中の置換、steer、review、compact では保持します。
  • # ファイル候補は Slash 候補と排他的です。Up/Down/Home/End/PageUp/PageDown、Enter/Tab、Escape、Ctrl+Enter の既存キー操作とアクセシビリティを維持します。

契約とデータフロー

  • Worker 契約 v15 に nullable な StartTurnRequest.Skill、SkillInvocationInfo { Name, Scope, Path }、検証済みメタデータ、SkillsChanged { Generation }、bridge の一覧操作を追加します。アイコン DTO/RPC は Remote UI の spike が成功するまで追加しません。
  • Extension が Remote UI に公開するのは不透明な選択 ID、安全化済み表示名、固定変換した scope label だけです。raw Path、URL、command、依存関係の transport 値、defaultPrompt 全文は data member にしません。
  • 全ての turn/start 直前に Worker が skills/list を force reload します。選択した Name + Scope + Path は、現在の enabled カタログ項目と完全一致しなければなりません。app-server へ送るのは { "type": "skill", "name": "...", "path": "..." } だけで、Scope と skill_approval はシリアライズしません。
  • 未知のスキル固有 approval request は fail-closed とし、既存の grant へ流しません。
  • skills/changed 通知、接続、再起動、切断で generation を進めます。古い完了結果が新しい snapshot を上書きすることはありません。

永続カタログキャッシュ (ADR-010)

Worker は既存の60秒のメモリ正本キャッシュに加えて、versioned な stale-while-revalidate snapshot を %LOCALAPPDATA%\\Kkamegawa.CodexForVisualStudio\\skill-catalog\\v1 に保存します。

  • キャッシュキーは正規化した workspace path の SHA-256 です。format version、Codex version、保存 UTC、generation 非依存の truncation 状態、検証済み表示/identity レコード最大200件を保存します。
  • hard expiry は24時間、workspace ごと4 MiB、全体64 MiBです。atomic な一時ファイル置換、LRU eviction、名前付き cross-process mutex、欠落・破損・過大・ロック中ファイルから live へ移る fail-open を適用します。
  • 保存するのは Name、Description、ShortDescription、DisplayName、Scope、Path、Enabled、正規化済み BrandColor だけです。DefaultPrompt、依存関係の値、errors、raw app-server JSON、icon path、Remote UI ID は保存しません。
  • 有効なディスクレコードは IsStale=true で直ちに返し、Extension では cached・選択不可として表示します。single-flight と TimeProvider によるバックグラウンド更新後、最新 generation だけを公開します。選択と turn 開始の正本は常に live skills/list です。
  • Extension は generation 付き表示 snapshot を保持し、Worker への取得はメニューを開くとき、TTL 切れ、通知受信時に限定します。キー入力ごとの RPC は行いません。

検索と表示

一つの仮想化リストに、組み込み行、Skills header、スキル行、loading/empty/unsupported/failed/cached/truncated の受動的な状態行を平坦化します。組み込みは既存の先頭 token 順位と8件上限を維持し、スキルは / 以降全体を検索して空白と dot を保持します。

スキルの順位は Name完全一致、DisplayName完全一致、Name前方一致、DisplayName前方一致、単語境界一致、Name/DisplayName部分一致、説明部分一致の順です。同順位は enabled、repo/user/system/admin/unknown の scope 順、表示名、Name、Path で安定化します。Worker の201件目以降は Worker-truncated 行として表示し、表示側の別上限とは混同しません。同名・同scope・別path は raw path を表示せず、Repository 1 of 2 のような安全な suffix で区別します。

メタデータは表示専用でフィールド単位に検証します。BrandColor は大文字の厳密な #RRGGBB で、小さな accent だけに使い High Contrast では非表示にします。DefaultPrompt は redaction、制御文字除去、4096文字上限を適用し、安全な preview だけを表示します。コンポーザーが空のときの明示操作でのみ挿入し、自動送信しません。依存関係は最大16件の plain-text badge/tooltip(type/value/descriptionに上限)だけで、実行、導入、readiness check、自動承認を行いません。

アイコン spike は未完了です。Extension 所有 cache URI の Image.Source が Remote UI で初回表示・更新できることを確認するまで固定 glyph を使い、icon RPC/DTO は有効化しません。成功時だけ、Worker の containment/PNG 検証、Extension の decode・metadata 除去・SHA-256 名・atomic publish、32ファイル/8 MiB LRU、複数VS間のlockを適用し、Remote UI へは cache URI だけを渡します。

実装フェーズ

  1. 契約と Worker: v15 DTO、厳密な serializer、正本メモリキャッシュ、永続キャッシュストア、invalidation/generation guard、sticky -32601、force reload、fail-closed identity 検証。
  2. 統合表示: 一つの仮想化 ListBox、組み込み8件、Worker が安全に受理したスキル最大200件、決定的な順位/衝突表示、状態行。
  3. コンポーザーのライフサイクル: 独立した一枠チップ、置換/削除、検索文字列だけの消去、Busy steer gate、default prompt の明示操作、アクセシビリティ/live region。
  4. メタデータとセキュリティ: フィールド別 fallback、SafeMarkdown/ISecretRedactor 境界、raw path 非公開、依存関係実行なし、固定 glyph icon gate。
  5. 検証と文書: Core/UI/cache/serialization/security テスト、warnings-as-errors の Debug/Release build、成果物と embedded XAML の hash、英日ドキュメントと本Wikiの同期。

受け入れ条件と検証

  • サーバーの0、1、20、21、200、201件を検証します。受理された全 identity がキーボードと UI Automation から到達でき、Worker truncation は明示されます。
  • stale から live への置換、TTL 境界、force reload、single-flight、通知 race、workspace 分離、破損/期限切れ/過大キャッシュ、atomic concurrent write、LRU cleanup、live fallback を検証します。
  • disabled/stale identity 拒否、3フィールドだけの turn serializer、Scope 非シリアライズ、skill_approval 非送信、チップ置換/削除/成功時のみ clear、Busy steer gate、# 排他、default prompt 非送信、メタデータ redaction/fallback、raw data member 回帰を検証します。
  • Debug/Release build、Core/UI 全テスト、VSIX/DLL/XAML hash、狭い幅と200% DPIの Dark/Light/Blue/High Contrast を確認します。Experimental Instance screenshot と icon spike は手動の後続ゲートです。

対象外

別のスキルパネルや mode toggle、新しい NuGet package、途中入力の Slash、iconLarge/SVG、任意の背景色、自動 prompt 送信、依存関係の実行/導入/readiness/自動承認、turn field の skill_approval は対象外です。

⚠️ **GitHub.com Fallback** ⚠️