commit f9a9b81ff74d6de679d4c84330bfc94bd5fabccd Author: ivanberry Date: Thu Mar 12 21:52:42 2026 +0800 feat: add register-skill composite action diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/register-skill/action.yaml b/register-skill/action.yaml new file mode 100644 index 0000000..f414e51 --- /dev/null +++ b/register-skill/action.yaml @@ -0,0 +1,144 @@ +name: 'Register Skill' +description: 'Standardized registration of a skill version to the business system' + +inputs: + client_key: + description: 'Authentication key for the business system' + required: true + api_base: + description: 'API gateway base URL' + default: 'https://api-gw-test.yuanwei-lnc.com' + skill_slug: + description: 'Override skill slug (defaults to package.json name or repo name)' + required: false + release_note: + description: 'Optional release note for this version' + required: false + default: '' + +runs: + using: "composite" + steps: + - name: Install runtime dependencies + shell: bash + run: | + set -e + apt-get update -qq + apt-get install -y -qq jq curl ca-certificates python3 + + - name: Load skill doc + shell: bash + env: + SKILL_SUBPATH: ${{ env.SKILL_SUBPATH }} + SKILL_DOC_PATH: ${{ env.SKILL_DOC_PATH }} + run: | + set -euo pipefail + DOC_PATH="${SKILL_DOC_PATH:-SKILL.md}" + BASE="${SKILL_SUBPATH:+$SKILL_SUBPATH/}" + ABS="${BASE}${DOC_PATH}" + + if [ ! -f "$ABS" ]; then + FALLBACK="${BASE}README.md" + if [ -f "$FALLBACK" ]; then + ABS="$FALLBACK" + DOC_PATH="README.md" + else + echo "ERROR: skill doc not found at $ABS" + exit 1 + fi + fi + + echo "Using doc: $ABS" + jq -Rs . < "$ABS" > /tmp/skill_doc.json + echo "RESOLVED_DOC_PATH=$DOC_PATH" >> "$GITHUB_ENV" + + - name: Register version + shell: bash + env: + INPUT_CLIENT_KEY: ${{ inputs.client_key }} + INPUT_API_BASE: ${{ inputs.api_base }} + INPUT_SKILL_SLUG: ${{ inputs.skill_slug }} + INPUT_RELEASE_NOTE: ${{ inputs.release_note }} + SKILL_SUBPATH: ${{ env.SKILL_SUBPATH }} + run: | + set -euo pipefail + + # Resolve slug: input → package.json → pyproject.toml → repo name + SLUG="${INPUT_SKILL_SLUG:-}" + BASE_DIR="${SKILL_SUBPATH:-.}" + + if [ -z "$SLUG" ] && [ -f "${BASE_DIR}/package.json" ]; then + SLUG=$(jq -r '.name // empty' "${BASE_DIR}/package.json" | sed 's|.*/||') + fi + + if [ -z "$SLUG" ] && [ -f "${BASE_DIR}/pyproject.toml" ]; then + SLUG=$(python3 -c " + import sys, tomllib + d = tomllib.load(open(sys.argv[1],'rb')) + print((d.get('project',{}).get('name') or d.get('tool',{}).get('poetry',{}).get('name') or '')) + " "${BASE_DIR}/pyproject.toml" 2>/dev/null || true) + SLUG="${SLUG##*/}" + fi + + if [ -z "$SLUG" ]; then + SLUG="${GITHUB_REPOSITORY##*/}" + fi + + echo "Registering slug=$SLUG version=${GITHUB_REF_NAME}" + + # Exchange client key for access token + SESSION_RES=$(curl -fsS -X POST "${INPUT_API_BASE}/auth/skill-credit/session" \ + -H "Content-Type: application/json" \ + -d "{\"clientKey\":\"${INPUT_CLIENT_KEY}\"}") + + ACCESS_TOKEN=$(echo "$SESSION_RES" | jq -r '.accessToken // empty') + if [ -z "$ACCESS_TOKEN" ]; then + echo "ERROR: failed to get access token" + echo "$SESSION_RES" + exit 1 + fi + + # Build and POST registration payload + RUNTIME_META=$(jq -nc \ + --arg entry "${SKILL_SUBPATH:+$SKILL_SUBPATH/}scripts" \ + '{entry_hint: $entry, provider: "forgejo"}') + + jq -n \ + --arg slug "$SLUG" \ + --arg ver "${GITHUB_REF_NAME}" \ + --arg note "${INPUT_RELEASE_NOTE:-}" \ + --arg url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" \ + --arg sub "${SKILL_SUBPATH:-}" \ + --arg ref "${GITHUB_REF_NAME}" \ + --arg sha "${GITHUB_SHA}" \ + --arg doc_p "${RESOLVED_DOC_PATH:-SKILL.md}" \ + --slurpfile doc_c /tmp/skill_doc.json \ + --argjson meta "$RUNTIME_META" \ + '{ + skill_slug: $slug, + version: $ver, + release_note: $note, + source_type: "git_ci", + repo_url: $url, + repo_subpath: $sub, + git_ref: $ref, + commit_sha: $sha, + skill_doc_path: $doc_p, + skill_doc_content: $doc_c[0], + runtime_meta: $meta + }' > /tmp/payload.json + + HTTP_CODE=$(curl -sS -o /tmp/register_response.json -w '%{http_code}' \ + -X POST "${INPUT_API_BASE}/ecom/skills/register-by-slug" \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + -H "Content-Type: application/json" \ + -d @/tmp/payload.json) + + if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then + echo "ERROR: registration failed HTTP $HTTP_CODE" + cat /tmp/register_response.json + exit 1 + fi + + echo "Registered successfully:" + cat /tmp/register_response.json