feat(004): add skillrig show for a human-friendly full skill view#19
feat(004): add skillrig show for a human-friendly full skill view#19so0k wants to merge 1 commit into
skillrig show for a human-friendly full skill view#19Conversation
Adds `skillrig show <skill>` (alias `info`), a Query-pattern command that prints ONE origin skill's complete record — most importantly its full, untruncated description, which `search` clips to ~80 chars and which a human otherwise could only recover via `--json | jq` (issue #17). show reuses search's resolver + catalog-load + convention-gate path (AP-04) and dispatches to a single new exact-name lookup primitive, skillcore.FindSkill. A named skill the origin does not publish is exit 1 with what/why/fix navigation (distinct from search, where an empty query is exit 0). --json emits {origin, skill} with the whole catalog entry. Co-evolution: extends the consolidated skillrig skill (routing row + references/show.md + description keywords), the cli.md command list + Query pattern classification, and the root README. Quickstart contract in specledger/004-show-skill/quickstart.md maps 1:1 to TestQuickstart_Show*. Closes #17 https://claude.ai/code/session_01SAczAuBfsd2hTEGrFBsmQZ
Review Summary by QodoAdd
WalkthroughsDescription• Adds skillrig show command with info alias for reading complete skill details • Implements exact-name lookup primitive FindSkill in skillcore for point-lookup matching • Renders full untruncated descriptions in human-friendly format and JSON output • Closes issue #17 by exposing complete skill records that search truncates to ~80 chars • Extends CLI documentation, skill routing, and integration test suite with show-specific scenarios Diagramflowchart LR
A["User invokes<br/>skillrig show SKILL"] --> B["Resolve origin<br/>via config/env"]
B --> C["Load catalog<br/>index.json"]
C --> D["FindSkill exact<br/>name lookup"]
D --> E["Render full record"]
E --> F["Human output<br/>with complete desc"]
E --> G["JSON output<br/>origin + skill"]
H["Unknown skill"] --> I["Exit 1 with<br/>what/why/fix"]
File Changes1. internal/cli/show.go
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
152 rules 1. show getwd error lacks fix
|
| cwd, err := sc.getwd() | ||
| if err != nil { | ||
| return &UsageError{Msg: "cannot determine working directory\nwhy: " + err.Error(), Cause: err} | ||
| } |
There was a problem hiding this comment.
1. show getwd error lacks fix 📘 Rule violation ⚙ Maintainability
The new show command returns a UsageError for working-directory failures without any remediation hint (no fix: line), violating the requirement that new error messages include actionable next steps. This can leave users stuck when os.Getwd fails (e.g., deleted CWD or permission issues).
Agent Prompt
## Issue description
The `show` command’s `cannot determine working directory` error includes `what` and `why` but no actionable `fix:` guidance, which violates the error-message compliance requirement.
## Issue Context
`internal/cli/show.go` returns `&UsageError{Msg: "cannot determine working directory\nwhy: ..."}` when `getwd()` fails.
## Fix Focus Areas
- internal/cli/show.go[82-85]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| // The whole point of show: the complete description, untruncated, set off by a | ||
| // blank line so it reads as the body of the record. | ||
| if desc := strings.TrimSpace(e.Description); desc != "" { | ||
| fmt.Fprintf(&b, "\n%s\n", desc) | ||
| } |
There was a problem hiding this comment.
2. rendershowresult prints full description 📘 Rule violation ⚙ Maintainability
The new human output path for show prints the full multi-line description without truncation/newline collapsing. This conflicts with the compliance requirement that human output descriptions be truncated to 80 characters and have newlines replaced with spaces.
Agent Prompt
## Issue description
Human output in `renderShowResult` prints `e.Description` verbatim (including newlines and unbounded length), but the checklist requires human descriptions to be truncated to 80 chars and newlines replaced with spaces.
## Issue Context
`renderShowResult` currently writes `desc := strings.TrimSpace(e.Description)` and then `fmt.Fprintf(&b, "\n%s\n", desc)`.
## Fix Focus Areas
- internal/cli/output.go[211-215]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| // showFooterPrefix is the next-step footer for a human show — the skill name is | ||
| // appended so the hint is a runnable command (cli.md Principle 3). | ||
| const showFooterPrefix = "→ vendor it: skillrig add " | ||
|
|
||
| // renderShowResult writes a single skill's full record to w. With jsonOut it | ||
| // emits one complete JSON object (origin + the whole catalog entry, all fields | ||
| // present); otherwise a human-friendly labelled block whose defining feature is | ||
| // the COMPLETE, untruncated description — the gap issue #17 closes, since search | ||
| // clips it to ~80 chars. The block is a fixed handful of header/field lines plus | ||
| // the description body and a footer hint. Data goes to stdout (the caller passes | ||
| // cmd.OutOrStdout()). | ||
| func renderShowResult(w io.Writer, origin string, e skillcore.CatalogEntry, jsonOut bool) error { | ||
| if jsonOut { | ||
| enc := json.NewEncoder(w) | ||
| enc.SetEscapeHTML(false) | ||
|
|
||
| return enc.Encode(showResultJSON{Origin: origin, Skill: e}) | ||
| } | ||
|
|
||
| var b strings.Builder | ||
|
|
||
| fmt.Fprintf(&b, "%s %s (%s)\n", e.Name, e.Version, e.Namespace) | ||
| fmt.Fprintf(&b, "path: %s\n", e.Path) | ||
|
|
||
| if len(e.Topics) > 0 { | ||
| fmt.Fprintf(&b, "topics: %s\n", strings.Join(e.Topics, ", ")) | ||
| } | ||
|
|
||
| if len(e.Requires) > 0 { | ||
| fmt.Fprintf(&b, "requires: %s\n", joinRequires(e.Requires)) | ||
| } | ||
|
|
||
| // The whole point of show: the complete description, untruncated, set off by a | ||
| // blank line so it reads as the body of the record. | ||
| if desc := strings.TrimSpace(e.Description); desc != "" { | ||
| fmt.Fprintf(&b, "\n%s\n", desc) | ||
| } | ||
|
|
||
| fmt.Fprintf(&b, "\n%s%s\n", showFooterPrefix, e.Name) | ||
|
|
There was a problem hiding this comment.
3. Footer hint breaks for names 🐞 Bug ≡ Correctness
renderShowResult prints a supposedly runnable skillrig add <name> footer using the raw catalog skill name, but valid skill names can start with - or include spaces, making the suggested command fail (flag parsing / shell splitting). This violates the stated contract that the footer is a runnable next-step command.
Agent Prompt
### Issue description
`renderShowResult` claims its footer is a runnable command, but it appends the raw skill name directly after `skillrig add `. Names are only validated as “single path segment” and may legally begin with `-` or contain spaces; in those cases the printed command is not runnable (cobra interprets `-foo` as a flag; shells split `foo bar`).
### Issue Context
- `renderShowResult` builds the footer via `showFooterPrefix + e.Name`.
- `validateSkillName` in skillcore does **not** reject leading `-` or spaces.
### Fix Focus Areas
- internal/cli/output.go[179-218]
### Implementation notes
- At minimum, make the command robust for leading-dash names by emitting `skillrig add -- <name>`.
- For full “runnable” behavior, add simple shell-quoting for names containing whitespace or other special chars (or tighten/align skill-name validation rules across the system if that’s the intended invariant).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
Verify agenskills.io specification on allowed characters in skill frontmatter field "name" - gh cli parsing logic of this metadata and if this is a real concern
Adds
skillrig show <skill>(aliasinfo), a Query-pattern command thatprints ONE origin skill's complete record — most importantly its full,
untruncated description, which
searchclips to ~80 chars and which ahuman otherwise could only recover via
--json | jq(issue #17).show reuses search's resolver + catalog-load + convention-gate path
(AP-04) and dispatches to a single new exact-name lookup primitive,
skillcore.FindSkill. A named skill the origin does not publish is exit 1
with what/why/fix navigation (distinct from search, where an empty query
is exit 0). --json emits {origin, skill} with the whole catalog entry.
Co-evolution: extends the consolidated skillrig skill (routing row +
references/show.md + description keywords), the cli.md command list +
Query pattern classification, and the root README. Quickstart contract in
specledger/004-show-skill/quickstart.md maps 1:1 to TestQuickstart_Show*.
Closes #17
https://claude.ai/code/session_01SAczAuBfsd2hTEGrFBsmQZ