Merge pull request #4 from Hestia-Homes/feature/hestia-skills-instlaled

Feature/hestia skills instlaled
This commit is contained in:
Jun-te Kim 2026-05-13 16:46:37 +01:00 committed by GitHub
commit b88fb554ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 234 additions and 88 deletions

3
.gitignore vendored
View file

@ -6,3 +6,6 @@ dist
.env.local
coverage
.vitest-cache
# skills CLI side-effects when running `skills add` locally
.agents/
.claude/

135
scripts/generate-lock.sh Executable file
View file

@ -0,0 +1,135 @@
#!/usr/bin/env bash
#
# Regenerate skills-lock.json from skills.config.json.
#
# How it works:
# 1. Read skills.config.json (list of {source, skills[]}).
# 2. In a temp dir, run `npx skills add <source> --skill ... --agent <agent> --copy --yes`
# once per source. The `skills` CLI auto-writes/merges skills-lock.json there.
# 3. Copy the resulting lock back to the repo root.
#
# Run from the repo root (or anywhere; paths are resolved relative to the script):
# bash scripts/generate-lock.sh
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
CONFIG="$REPO_ROOT/skills.config.json"
DEST_LOCK="$REPO_ROOT/skills-lock.json"
if [[ ! -f "$CONFIG" ]]; then
echo "error: $CONFIG not found." >&2
exit 1
fi
for bin in node npx; do
if ! command -v "$bin" >/dev/null 2>&1; then
echo "error: $bin is required (install Node.js >= 20)." >&2
exit 1
fi
done
WORK_DIR="$(mktemp -d -t skills-lockgen.XXXXXX)"
trap 'rm -rf "$WORK_DIR"' EXIT
# Emit "agent\ninstallSource\tcanonicalSource\tskillA,skillB\n..." for the shell.
# installSource is what we pass to `skills add` (resolved localPath if set, else
# the canonical slug). canonicalSource is what the published lock must record.
PLAN_FILE="$WORK_DIR/plan.txt"
node --input-type=module -e "
import fs from 'node:fs';
import path from 'node:path';
const cfg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
const repoRoot = process.argv[3];
const agent = cfg.agent || 'claude-code';
const lines = [agent];
for (const entry of cfg.sources || []) {
if (!entry?.source || !Array.isArray(entry.skills) || entry.skills.length === 0) continue;
const install = entry.localPath ? path.resolve(repoRoot, entry.localPath) : entry.source;
lines.push(install + '\t' + entry.source + '\t' + entry.skills.join(','));
}
fs.writeFileSync(process.argv[2], lines.join('\n') + '\n');
" "$CONFIG" "$PLAN_FILE" "$REPO_ROOT"
AGENT="$(head -n1 "$PLAN_FILE")"
echo "==> Agent target: $AGENT"
echo "==> Generating lock in $WORK_DIR"
# Read plan from fd 3 so the loop body's stdin stays free for npx (the skills
# CLI reads stdin even in --yes mode and would otherwise gobble loop lines).
while IFS=$'\t' read -r INSTALL_SOURCE CANONICAL_SOURCE SKILLS <&3; do
[[ -z "$INSTALL_SOURCE" ]] && continue
if [[ "$INSTALL_SOURCE" == "$CANONICAL_SOURCE" ]]; then
echo "==> $CANONICAL_SOURCE :: $SKILLS"
else
echo "==> $CANONICAL_SOURCE (from local $INSTALL_SOURCE) :: $SKILLS"
fi
SKILL_ARGS=()
IFS=',' read -ra _NAMES <<< "$SKILLS"
for n in "${_NAMES[@]}"; do
[[ -z "$n" ]] && continue
SKILL_ARGS+=(--skill "$n")
done
( cd "$WORK_DIR" && npx --yes skills@latest add "$INSTALL_SOURCE" \
"${SKILL_ARGS[@]}" \
--agent "$AGENT" \
--copy \
--yes < /dev/null )
done 3< <(tail -n +2 "$PLAN_FILE")
if [[ ! -f "$WORK_DIR/skills-lock.json" ]]; then
echo "error: skills CLI did not produce $WORK_DIR/skills-lock.json." >&2
exit 1
fi
# Rewrite any local-path sources in the lock back to their canonical slug, so
# consumers of skills-lock.json (e.g. setup.sh in a dev container) fetch from
# GitHub instead of a path that only exists on the generator's machine.
node --input-type=module -e "
import fs from 'node:fs';
import path from 'node:path';
const cfg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
const repoRoot = process.argv[2];
const lock = JSON.parse(fs.readFileSync(process.argv[3], 'utf8'));
const remap = new Map();
for (const entry of cfg.sources || []) {
if (!entry?.source || !entry.localPath) continue;
remap.set(path.resolve(repoRoot, entry.localPath), entry.source);
}
for (const skill of Object.values(lock.skills || {})) {
if (!skill?.source) continue;
const resolved = path.resolve(skill.source);
if (remap.has(resolved)) {
skill.source = remap.get(resolved);
skill.sourceType = 'github';
}
}
fs.writeFileSync(process.argv[4], JSON.stringify(lock, null, 2) + '\n');
" "$CONFIG" "$REPO_ROOT" "$WORK_DIR/skills-lock.json" "$DEST_LOCK"
echo "==> Wrote $DEST_LOCK"
# Cross-check: every (source, skill) requested in config should be present in the lock.
node --input-type=module -e "
import fs from 'node:fs';
const cfg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
const lock = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
const got = new Map();
for (const [name, entry] of Object.entries(lock.skills || {})) {
if (!entry?.source) continue;
if (!got.has(entry.source)) got.set(entry.source, new Set());
got.get(entry.source).add(name);
}
const missing = [];
for (const entry of cfg.sources || []) {
const have = got.get(entry.source) || new Set();
for (const s of entry.skills || []) {
if (!have.has(s)) missing.push(entry.source + '::' + s);
}
}
if (missing.length) {
console.error('error: skills missing from generated lock (likely missing SKILL.md frontmatter upstream):');
for (const m of missing) console.error(' - ' + m);
process.exit(1);
}
console.log('==> Verified: all ' + Object.keys(lock.skills).length + ' configured skills present in lock.');
" "$CONFIG" "$DEST_LOCK"

View file

@ -1,114 +1,86 @@
{
"version": 3,
"version": 1,
"skills": {
"diagnose": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/diagnose/SKILL.md",
"skillFolderHash": "43d464d0e9d1049b9d525975c0f7367ab7e01a5f",
"pluginName": "mattpocock-skills"
},
"grill-with-docs": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/grill-with-docs/SKILL.md",
"skillFolderHash": "2969a1224c70fe41b9dd2ddbe32c2ec62f2815bd",
"pluginName": "mattpocock-skills"
},
"improve-codebase-architecture": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/improve-codebase-architecture/SKILL.md",
"skillFolderHash": "3ad8fa787b3b9b622d1f5a3d0afc27812ac782fa",
"pluginName": "mattpocock-skills"
},
"setup-matt-pocock-skills": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/setup-matt-pocock-skills/SKILL.md",
"skillFolderHash": "a500c5b9a481e6fac8c9bb87cd4c4e16c3f46e1a",
"pluginName": "mattpocock-skills"
},
"to-issues": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/to-issues/SKILL.md",
"skillFolderHash": "2bf2903405724ce27038fc91f1c4304c4a63ae16",
"pluginName": "mattpocock-skills"
},
"to-prd": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/to-prd/SKILL.md",
"skillFolderHash": "63e890f04a30b69c9931615f36700fc45eb8d1ad",
"pluginName": "mattpocock-skills"
},
"triage": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/triage/SKILL.md",
"skillFolderHash": "de4f182c30876a2460ca307e2f601b9b892527e5",
"pluginName": "mattpocock-skills"
},
"zoom-out": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/engineering/zoom-out/SKILL.md",
"skillFolderHash": "6ecebabdea814d12888f56a611da7bf182b5fb26",
"pluginName": "mattpocock-skills"
},
"caveman": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/productivity/caveman/SKILL.md",
"skillFolderHash": "17972a1bdbf5909b9dbdc435ad348f0bf45f8664",
"pluginName": "mattpocock-skills"
"computedHash": "934433479903febc585bf6deb5f0cebc63137e3f86b7babe0aab1ecb94d6d7a4"
},
"diagnose": {
"source": "mattpocock/skills",
"sourceType": "github",
"skillPath": "skills/engineering/diagnose/SKILL.md",
"computedHash": "15939a26f86edec2d4862042b8564e5a062cb81d04e047a0cea6305c8830b5f5"
},
"grill-me": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/productivity/grill-me/SKILL.md",
"skillFolderHash": "2a1ad17028306ebe45f0e49703fa28b9b2e7f499",
"pluginName": "mattpocock-skills"
"computedHash": "784f0dbb7403b0f00324bce9a112f715342777a0daee7bbb7385f9c6f0a170ea"
},
"write-a-skill": {
"grill-with-docs": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/mattpocock/skills.git",
"skillPath": "skills/productivity/write-a-skill/SKILL.md",
"skillFolderHash": "2f252b35aa238879afc5a230ac30343708dee0b3"
"skillPath": "skills/engineering/grill-with-docs/SKILL.md",
"computedHash": "1adf321072f53cce3dcaf5357d91b8230d4aa647bb8a51756745337a6ee567b8"
},
"improve-codebase-architecture": {
"source": "mattpocock/skills",
"sourceType": "github",
"skillPath": "skills/engineering/improve-codebase-architecture/SKILL.md",
"computedHash": "c77b86b4332919499608f9af1880074e1fec65a59b95c70c27a9f39cd137865e"
},
"ralph-loop": {
"source": "Hestia-Homes/agentic-toolkit",
"sourceType": "github",
"sourceUrl": "https://github.com/Hestia-Homes/agentic-toolkit.git",
"skillPath": "skills/engineering/ralph-loop/SKILL.md",
"skillFolderHash": "d1414d3ccd3cc27f7cc1117b7723efc22b2d1ec7"
"computedHash": "6d6c256a5145008038d128089fa17ed78ac9350d98efd977624da21d9255988b"
},
"to-project": {
"source": "Hestia-Homes/agentic-toolkit",
"setup-matt-pocock-skills": {
"source": "mattpocock/skills",
"sourceType": "github",
"sourceUrl": "https://github.com/Hestia-Homes/agentic-toolkit.git",
"skillPath": "skills/engineering/to-project/SKILL.md",
"skillFolderHash": "c28e88e90052bee0dfddc8c525462fe339ff2244"
"skillPath": "skills/engineering/setup-matt-pocock-skills/SKILL.md",
"computedHash": "0164a8b1ef998abca426056c6ed8a7716a9d4692fc6daa5378f68381a6dafd24"
},
"tdd": {
"source": "Hestia-Homes/agentic-toolkit",
"sourceType": "github",
"sourceUrl": "https://github.com/Hestia-Homes/agentic-toolkit.git",
"skillPath": "skills/engineering/tdd/SKILL.md",
"skillFolderHash": "6690fa8a3dcb7a91ef6043b542322553e199e35b"
"computedHash": "b995b2494d7cd0737c7aa2d6a8affcdd8030ac1b29a52c572a3c5c163842c451"
},
"to-issues": {
"source": "mattpocock/skills",
"sourceType": "github",
"skillPath": "skills/engineering/to-issues/SKILL.md",
"computedHash": "47f648f3414848ccfc62cb41d2828b7e575fb5e7cbd6c4bdf630c063b5dc5e82"
},
"to-prd": {
"source": "mattpocock/skills",
"sourceType": "github",
"skillPath": "skills/engineering/to-prd/SKILL.md",
"computedHash": "6d741474efd4bc3db55fabc2722ed78ca9c374cabcb6212936d79d4fd4a30fcb"
},
"to-project": {
"source": "Hestia-Homes/agentic-toolkit",
"sourceType": "github",
"computedHash": "59daf039ac699a44a9416f8ec403b83d4166e05489959e127746231ff8be4e12"
},
"triage": {
"source": "mattpocock/skills",
"sourceType": "github",
"skillPath": "skills/engineering/triage/SKILL.md",
"computedHash": "2b6efb6da12d92551772fcc04acf331f4e0e6f7bd9d4cb23ce0b301e0b128feb"
},
"write-a-skill": {
"source": "mattpocock/skills",
"sourceType": "github",
"skillPath": "skills/productivity/write-a-skill/SKILL.md",
"computedHash": "b44d8aab2ead83c716e01af4c9a24ccc4575ce70ad58ec4f1749fb88c9cc82ba"
},
"zoom-out": {
"source": "mattpocock/skills",
"sourceType": "github",
"skillPath": "skills/engineering/zoom-out/SKILL.md",
"computedHash": "8357aeaece3b709c442eab67e64b86844e05e2f1ea95b109565eba50b6def36e"
}
},
"dismissed": {}
}
}

31
skills.config.json Normal file
View file

@ -0,0 +1,31 @@
{
"$schema_comment": "Source of truth for skills-lock.json. Edit this then run scripts/generate-lock.sh.",
"agent": "claude-code",
"sources": [
{
"source": "mattpocock/skills",
"skills": [
"diagnose",
"grill-with-docs",
"improve-codebase-architecture",
"setup-matt-pocock-skills",
"to-issues",
"to-prd",
"triage",
"zoom-out",
"caveman",
"grill-me",
"write-a-skill"
]
},
{
"source": "Hestia-Homes/agentic-toolkit",
"localPath": ".",
"skills": [
"ralph-loop",
"to-project",
"tdd"
]
}
]
}

View file

@ -1,3 +1,8 @@
---
name: tdd
description: Test-driven development using vertical 3A slices. Use when adding behavior, fixing a bug that lacks a regression test, or any work where making a failing test pass is the right unit of progress.
---
# Test-Driven Development (3A)
## Philosophy