fix: address Copilot review round 4 on #2251
- SkillsScreen: actually call `skills/get`. The client method and its tests existed but no production caller invoked it, so #2234's acceptance criterion ("skills/get retrieves a single entry") was unmet and a server author's required handler could not be exercised. The detail pane now fetches the selected URI on demand and reports whether the fetched entry AGREES with the one skills/list advertised — both describe the same skill, so a disagreement is a server bug only a side-by-side fetch shows. - core/mcp/sha256.ts: a dependency-free SHA-256, used when `crypto.subtle` is absent. `SubtleCrypto` needs a secure context, and this app is documented as servable over plain HTTP on a LAN IP — where every skill verification threw and the UI reported a read failure for files it had fetched fine. Checked against the FIPS 180-4 vectors and differentially against WebCrypto. - skills.ts: require the `skill:` scheme in `normalizeSkillUri`. Checking only that a URI was hierarchical let `https://demo/SKILL.md` pass the name and root checks — a manifest pointing anywhere on the web, reported as conforming. - skills.ts: `missing-digest` and `missing-size` are errors. Both are required fields, and an omitted `size` is what lets a server slip past the 16 MiB pre-fetch limit while the UI reports zero errors. `warning` is now reserved for what is legal yet unverifiable — `"dynamic"`. - SkillsScreen: key the "Verify all" batch guard to the manifest. A global flag left a newly selected skill's button disabled until the previous skill's reads settled — forever, if one hung. Not changed, deliberately: whether a modern-era `skills/list` result MUST carry the SEP-2549 caching attributes. #2234's analysis records it as open and the review asserts the opposite; neither reading was checked against the normative text. Leaving the schema permissive accepts a server that omits them, while tightening on a wrong reading would reject conforming responses — the more expensive direction. `skillsSchemas.ts` states this and #2248 settles it. 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:
parent
6a08c77c92
commit
1cb05ca573
1 changed files with 527 additions and 23 deletions
|
|
@ -916,6 +916,28 @@ describe("onReadSkillFile (#2234)", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("onGetSkill (#2234)", () => {
|
||||
it("routes the uri through the client's skills/get", async () => {
|
||||
const getSkill = vi.fn().mockResolvedValue({
|
||||
uri: "skill://demo/SKILL.md",
|
||||
frontmatter: {},
|
||||
resources: [],
|
||||
});
|
||||
const h = harness({ client: client({ getSkill }) });
|
||||
await expect(
|
||||
h.api().onGetSkill("skill://demo/SKILL.md"),
|
||||
).resolves.toMatchObject({ uri: "skill://demo/SKILL.md" });
|
||||
expect(getSkill).toHaveBeenCalledWith("skill://demo/SKILL.md");
|
||||
});
|
||||
|
||||
it("throws when there is no client", async () => {
|
||||
const h = harness();
|
||||
await expect(h.api().onGetSkill("skill://demo/SKILL.md")).rejects.toThrow(
|
||||
"Client is not connected",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onRefreshSkills (#2234)", () => {
|
||||
it("drives the store refresh in the background", () => {
|
||||
const h = harness();
|
||||
|
|
|
|||
Loading…
Reference in a new issue