feat(skills): address Copilot review round 16 on #2234

Round 16 reported no inline comments and three suppressed findings, all
valid:

- `getSkillsExtension` treated a non-object extension value (`false`,
  `"skills"`) as a declaration. SEP-2133 declares an extension as an
  object of sub-options, so a primitive is not one — now rejected,
  matching `appElicitation.ts`.
- The `onGetSkill` prop doc claimed the two responses "must agree" and
  that a difference means a broken server, contradicting the
  implementation, which reports a difference as a finding rather than a
  fault. Reworded to what the code does.
- No real-transport test exercised the fixture's `skills/*` handlers.
  Added `src/test/integration/mcp/inspectorClient-skills.test.ts`,
  parameterized over both protocol eras: capability advertisement, the
  paged `skills/list` walk (direct and through `ManagedSkillsState`),
  `skills/get`, the `-32602` for an unknown URI, `resources/read` of a
  skill file, and delegation of an ordinary resource through the
  fixture's `resources/read` wrapper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018kfrH3uRNUM4JAk1reKtyY
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-05 02:42:47 -04:00
commit 1ee958091e

View file

@ -127,10 +127,15 @@ export interface SkillsScreenProps {
/** Fetch one skill file's contents via `resources/read`, on demand. */
onReadSkillFile: (uri: string) => Promise<SkillFileContents>;
/**
* Re-fetch the selected entry through `skills/get` (SEP-2640). Distinct from
* the entry `skills/list` already returned, and the point of exercising it is
* that the two must agree: a server whose `skills/get` disagrees with its own
* listing is broken in a way only a side-by-side fetch can show.
* Re-fetch the selected entry through `skills/get` (SEP-2640) — the
* extension's second required method, which nothing else in the app calls.
*
* It is a **fresh point-in-time snapshot**, so a conforming result may
* legitimately differ from an older listing, and the screen presents a
* difference as an updated snapshot rather than a fault. What it does treat
* as a fault is the fetched entry being non-conforming in its own right, or
* answering for a different URI than the one requested — neither of which a
* fresh read excuses.
*/
onGetSkill: (uri: string) => Promise<SkillEntry>;
}