k-skill/scripts/validate-skills.sh
Jeffrey (Dongkyu) Kim f348cb4f85
feat: Manus.ai 호환 import 경로 추가 (GitHub URL + rolling .skill 번들) (#227)
* docs: add Manus.ai GitHub skill import guide

Manus.ai의 'GitHub에서 프로젝트 스킬 가져오기' 기능은 폴더 루트에 SKILL.md(YAML frontmatter name/description 필수)가 있는 디렉토리 URL을 받는다. k-skill의 모든 스킬은 이미 이 포맷을 만족하므로 코드 변경 없이 문서만 추가한다.

- 사용자는 저장소 루트 URL(https://github.com/NomaDamas/k-skill) 대신 개별 스킬 폴더 URL(https://github.com/NomaDamas/k-skill/tree/main/<skill-name>)을 붙여 넣어야 한다.

- 기존 frontmatter(license, metadata.*)는 Manus가 무시하지만 다른 코딩 에이전트와의 호환을 위해 그대로 유지한다.

* feat: add build:manus-bundle for batch .skill upload to Manus.ai

Per-folder GitHub URL import is tedious for 61 skills, so add 'npm run build:manus-bundle' which emits one .skill (ZIP) per skill into dist/manus/, plus a single k-skill-manus-all.zip convenience bundle and an INDEX.md listing. Each archive nests its content under <skill-name>/ to match the public Anthropic skill-creator packager layout.

Manus does NOT support multi-skill bulk import in a single archive (verified against help.manus.im, manus.im/docs, and open.manus.ai API docs). The combined zip is purely a download convenience: users still drag-drop individual .skill files into Manus, but the file picker accepts multiple selections so it's still much faster than pasting 61 GitHub URLs.

- scripts/build-manus-bundle.js: discovers root-level skills (mirrors validate-skills.sh exclusions), shells out to system zip with -X for reproducible archives, excludes node_modules/__pycache__/.DS_Store.

- scripts/test_build_manus_bundle.js: validates discovery, frontmatter parsing, lockstep with validate-skills.sh, and docs coverage.

- scripts/validate-skills.sh: also skip dist/ and .sisyphus/ so the validator stays clean after a build.

- .gitignore: ignore dist/ and .sisyphus/.

- docs/install-manus.md: document both Method A (GitHub URL) and Method B (.skill bundle).

* ci: auto-publish Manus .skill bundle as rolling release on main push

Every push to main that touches a skill folder or the bundler now builds the .skill bundle and publishes it to the GitHub Releases tag 'manus-bundle-latest' (marked prerelease so it does not pollute the Latest release pointer used by the npm release flow).

Users get stable download URLs that always point to the latest build:

  - https://github.com/NomaDamas/k-skill/releases/download/manus-bundle-latest/k-skill-manus-all.zip

  - https://github.com/NomaDamas/k-skill/releases/download/manus-bundle-latest/INDEX.md

This removes the 'clone the repo and run npm' step for non-developers. The direct-build path remains documented as the developer fallback.

- .github/workflows/manus-bundle.yml: workflow_dispatch + push-to-main with paths filter, uses preinstalled gh CLI (no third-party release action), concurrency-grouped so overlapping pushes do not race on the same tag, --clobber upload to keep asset URLs stable.

- docs/install-manus.md: new 'quick path' section with the rolling-release URLs; existing local-build section reframed as a developer fallback.

- scripts/test_build_manus_bundle.js: 2 new tests pinning the doc URLs and key workflow invariants (trigger branch, build invocation, tag, asset name, prerelease flag, write permission).
2026-05-11 12:12:44 +09:00

64 lines
1.5 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
status=0
while IFS= read -r -d '' skill_dir; do
skill_name="$(basename "$skill_dir")"
skill_file="$skill_dir/SKILL.md"
if [[ ! -f "$skill_file" ]]; then
echo "missing SKILL.md: $skill_name"
status=1
continue
fi
if ! head -n 1 "$skill_file" | grep -qx -- "---"; then
echo "missing frontmatter start: $skill_file"
status=1
fi
if ! grep -q '^name: ' "$skill_file"; then
echo "missing name field: $skill_file"
status=1
fi
if ! grep -q '^description: ' "$skill_file"; then
echo "missing description field: $skill_file"
status=1
fi
declared_name="$(sed -n 's/^name: //p' "$skill_file" | head -n 1 | tr -d '"')"
if [[ "$declared_name" != "$skill_name" ]]; then
echo "name mismatch: $skill_file declares '$declared_name' but directory is '$skill_name'"
status=1
fi
done < <(
find "$root" -mindepth 1 -maxdepth 1 -type d \
! -name .git \
! -name .github \
! -name .codex \
! -name .claude \
! -name .omx \
! -name .ouroboros \
! -name .changeset \
! -name .cursor \
! -name .vscode \
! -name .sisyphus \
! -name .idea \
! -name dist \
! -name docs \
! -name node_modules \
! -name packages \
! -name python-packages \
! -name scripts \
! -name examples \
-print0
)
if [[ "$status" -ne 0 ]]; then
exit "$status"
fi
echo "skill layout looks valid"