fix: address Copilot review round 2 on #2248
Four findings, two of them silent holes in the verification itself. **A blob-served SKILL.md skipped the frontmatter check entirely.** The entry's own file was captured as `contents.text`, so a server returning the markdown as a base64 `blob` — a legal `resources/read` shape this module already decodes for the digest — never reached the comparison, and the report still said `ok`. A MUST that quietly did not run. The file is now held as bytes and the text derived from them, which also guarantees the digest and the frontmatter describe one snapshot. **A dynamic skill whose SKILL.md could not be read reported `ok: true`.** It has no manifest rows, so `files` stayed empty, and its only static finding is a warning — a verification that could not be performed was reported as one that passed. The fallback read now records a `read-error` for all three ways it can fail. It is gated on `manifestListsSelf` (by normalized identity) so a self-entry the manifest listed and failed to read is not read, or reported, twice. **A served `.nan` compared equal to a listed `null`.** YAML expresses non-finite numbers, JSON does not, and `JSON.stringify` turns all of them into `null` — so the canonical comparison reported a real mismatch as agreement. Verified against the parser before fixing. They now canonicalize to a form no JSON scalar can equal, and the value is named in the finding. Also: the self-entry match is by normalized identity rather than raw string, which stops a second read and stops this function disagreeing with `checkSkillConformance`; and `SkillsTab.tsx` gains the file header AGENTS.md requires. The four `err instanceof Error` ternaries are one `reasonOf` helper now — extracted because the coverage gate found every one of their non-Error arms uncovered, and one honestly-tested branch beats four ignores. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ND46Ci64DC3tzBy9aG81Nc Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
4fa00d1cfd
commit
033600e4ca
1 changed files with 288 additions and 13 deletions
|
|
@ -1,3 +1,23 @@
|
|||
/**
|
||||
* The TUI's Skills pane — the SEP-2640 catalog in a terminal (#2248).
|
||||
*
|
||||
* **Why the TUI owns a pane rather than reusing the web screen's logic.** It
|
||||
* does reuse everything that decides an answer: `checkSkillConformance`,
|
||||
* `checkSkillNameCollisions` and `verifySkills` all live in `core/` and are
|
||||
* driven identically here, so a verdict cannot differ depending on which client
|
||||
* you asked. What is local is presentation, and the terminal's constraints are
|
||||
* genuinely different — two panes in 80 columns, no colour to rely on, and a
|
||||
* keyboard rather than a pointer.
|
||||
*
|
||||
* ⚠️ **Severity is carried by a glyph as well as a colour** (`✓` / `!` / `✗`).
|
||||
* This pane is read over ssh, inside tmux, and piped through `script(1)`, where
|
||||
* colour may not survive; a row whose only signal was `red` would then be
|
||||
* indistinguishable from a clean one.
|
||||
*
|
||||
* The pane is shown only when the connected server declares the extension —
|
||||
* that gate, and the reset that leaves the tab when it goes false, live in
|
||||
* `App.tsx` because they are navigation concerns rather than this pane's.
|
||||
*/
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Box, Text, useInput, type Key } from "ink";
|
||||
import { ScrollView, type ScrollViewRef } from "ink-scroll-view";
|
||||
|
|
|
|||
Loading…
Reference in a new issue