feat(cli): skillforge ls — list installed skills - #19
Conversation
|
Warning Review limit reached
More reviews will be available in 11 minutes and 10 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What
skillforge ls— list installed skills in~/.claude/skills/(the defaultinstalltarget) with name, version, and absolute path pulled from each skill'sSKILL.mdfrontmatter. Thenpm lsanalogue for the Claude skills tree.The human-readable mode prints a tidy 3-column table —
Name Version Path— with column widths sized to actual content so narrow trees stay compact and long names still align. Sentence-case heading in tracked uppercase keeps the section signal quiet rather than editorial. Empty-state message names the scanned directory so the reader knows which tree came up empty.Why
installwrites to~/.claude/skills/<skill-name>/by default. Once a user has installed more than two or three skills, the natural follow-up is "what have I got?" — and the honest answer was "golsthe directory yourself, thencat SKILL.mdon each one to see the version". This command closes that loop with a single read-only directory scan. No network, no writes, no surprises.Semantics
~/.claude/skills/— same pathinstallwrites to.--from <dir>overrides for tests and alt-trees.SKILL.mdat its top level. Loose files at the parent level get ignored silently; child dirs without aSKILL.mdare skipped silently too — a half-pulled install shouldn't pollute everylsinvocation.SKILL.mdfrontmatter runs through the sameSkillFrontmatterSchemathatinstallenforces. Invalid skills are excluded from the count by default;--include-invalidflips that to "include them withvalid: falseand anissueslist" — useful when debugging "why isn't my skill showing up".--from <dir>that doesn't exist → empty result, exit 0. A fresh machine with no~/.claude/skills/yet is not an error; the honest answer is "zero installed", same asnpm lsin an empty project.--fromis a filesourcediscriminatorInstalledSkill:"dir". Future-proofs the shape for.skillarchive listings later (e.g.ls ~/.claude/skills-cache --bundles).lsis read-only end-to-end — no fetching, no writing, no temp files.Implementation — minimal and additive
src/ls.ts(~140 LOC of which ~50 is essence):listInstalledSkills({ fromDir?, includeInvalid? })returns{ fromDir, count, skills }. Reusesgray-matter(already on deps forvalidate/lint/inspect) andSkillFrontmatterSchemafromschema.ts.src/cli.ts: newlscommand with--from,--include-invalid,--jsonflags, plus a tidy 3-column table renderer (printLsReport) and an empty-state message that names the scanned directory.src/index.ts: exportslistInstalledSkills,LsOptions,LsResult,InstalledSkillso library consumers can build on the same API the CLI uses.README.md: new### skillforge lssection aftercat, status line and roadmap bumped.install.ts/cat.ts/skill-loader.ts/validate.ts/lint.ts/pack.ts/inspect.ts/diff.ts/tree.ts/update.ts/init.ts/format.ts.gray-matterandzod(viaSkillFrontmatterSchema).Tests
12 new tests in
src/ls.test.ts, written test-first per §17:--from→count: 0,skills: [].count: 1, name + version match frontmatter,source: "dir",valid: true.name.descriptiontoo short → only the valid one appears,count: 1.--include-invalid→ both appear, broken one hasvalid: falseand anissues[]array; valid one has noissuesfield.--fromoverridefromDirreflected inLsResult.fromDir.--from /does/not/exist→ empty result, no throw.--fromis a fileSKILL.mdLsResultshapeObject.keysexactly["count", "fromDir", "skills"]; validInstalledSkillkeys exactly["name", "path", "source", "valid", "version"](noissues)..DS_Store) are ignored, not counted.fromDirfromDir→ resolves to~/.claude/skills; doesn't assert count (user state-dependent).The red→green transition I captured during development: with
ls.test.tswritten andls.tsnot yet created,vitest run src/ls.test.tsfailed withError: Failed to load url ./ls.js (resolved id: ./ls.js) in /private/tmp/skillforge-ls/src/ls.test.ts. Does the file exist?— exactly the failure the spec calls for. After implementingsrc/ls.ts, the samevitest runreturned✓ src/ls.test.ts (12 tests) 57mson the first pass.Gates
pnpm installtsc --noEmitbiome check src(--fix --unsafe)vitest runtsupbuild/tmp/sf-ls-smoke/skills→./dist/cli.js ls --from …--json | jq .countreturns3--include-invalidon a broken skill(invalid)tag, dimmedDon't refactor
No changes to
install.ts/cat.ts/skill-loader.ts/validate.ts/lint.ts/pack.ts/inspect.ts/diff.ts/tree.ts/update.ts/init.ts/format.ts. No new runtime deps.SkillFrontmatterSchemareused as-is.Declaration of AI-Tools / LLMs usage