diff --git a/.github/workflows/skill-review-check.yml b/.github/workflows/skill-review-check.yml new file mode 100644 index 0000000..2e6a316 --- /dev/null +++ b/.github/workflows/skill-review-check.yml @@ -0,0 +1,156 @@ +name: Skill Review Check + +# Polls npm daily to detect new @needle-tools/engine releases. +# When a new version is found (compared to the version stamp in SKILL.md), +# opens a GitHub Issue to trigger a manual skill review. + +on: + schedule: + # Run daily at 08:00 UTC + - cron: '0 8 * * *' + workflow_dispatch: + inputs: + force_version: + description: 'Force a specific version to create a review issue for (e.g. 4.16.0). Leave blank to auto-detect.' + required: false + default: '' + +jobs: + check-and-notify: + runs-on: ubuntu-latest + permissions: + issues: write + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Read skill version stamp + id: skill_version + run: | + # Extract the reviewed-against version from SKILL.md frontmatter or body + STAMP=$(grep -o 'reviewed-against:.*"@needle-tools/engine@[^"]*"' \ + providers/claude/plugin/skills/needle-engine/SKILL.md \ + | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "") + + if [ -z "$STAMP" ]; then + echo "::warning::Could not find reviewed-against stamp in SKILL.md" + STAMP="0.0.0" + fi + echo "stamp=$STAMP" >> $GITHUB_OUTPUT + echo "Skill last reviewed against: $STAMP" + + - name: Fetch latest npm version + id: npm_version + run: | + if [ -n "${{ github.event.inputs.force_version }}" ]; then + LATEST="${{ github.event.inputs.force_version }}" + echo "Using forced version: $LATEST" + else + LATEST=$(curl -sf https://registry.npmjs.org/@needle-tools/engine/latest \ + | grep -o '"version":"[^"]*"' | head -1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+') + fi + + if [ -z "$LATEST" ]; then + echo "::error::Failed to fetch npm version" + exit 1 + fi + echo "latest=$LATEST" >> $GITHUB_OUTPUT + echo "Latest npm version: $LATEST" + + - name: Compare versions + id: compare + run: | + STAMP="${{ steps.skill_version.outputs.stamp }}" + LATEST="${{ steps.npm_version.outputs.latest }}" + + # Use sort -V for semantic version comparison + HIGHER=$(printf '%s\n%s' "$STAMP" "$LATEST" | sort -V | tail -1) + + if [ "$HIGHER" = "$LATEST" ] && [ "$LATEST" != "$STAMP" ]; then + echo "new_version=true" >> $GITHUB_OUTPUT + echo "New version detected: $STAMP → $LATEST" + else + echo "new_version=false" >> $GITHUB_OUTPUT + echo "No new version (skill is at $STAMP, npm is at $LATEST)" + fi + + - name: Check for existing open review issue + id: existing_issue + if: steps.compare.outputs.new_version == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + LATEST="${{ steps.npm_version.outputs.latest }}" + # Search for an already-open issue for this exact version + EXISTING=$(gh issue list \ + --repo ${{ github.repository }} \ + --state open \ + --label "skill-review" \ + --search "Skill review needed — @needle-tools/engine v${LATEST}" \ + --json number \ + --jq '.[0].number // ""') + + echo "existing=$EXISTING" >> $GITHUB_OUTPUT + if [ -n "$EXISTING" ]; then + echo "Issue #$EXISTING already exists for v$LATEST, skipping." + fi + + - name: Open skill review issue + if: steps.compare.outputs.new_version == 'true' && steps.existing_issue.outputs.existing == '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + LATEST="${{ steps.npm_version.outputs.latest }}" + STAMP="${{ steps.skill_version.outputs.stamp }}" + SKILL_URL="https://github.com/${{ github.repository }}/blob/main/providers/claude/plugin/skills/needle-engine/SKILL.md" + NPM_URL="https://www.npmjs.com/package/@needle-tools/engine?activeTab=versions" + CHANGELOG_URL="https://github.com/needle-tools/needle-tiny/releases" + + gh issue create \ + --repo ${{ github.repository }} \ + --title "Skill review needed — @needle-tools/engine v${LATEST} released" \ + --assignee "kaktus-klaus" \ + --label "skill-review" \ + --body "$(cat <\` web component attributes changed + - [ ] Review any deprecated APIs referenced in SKILL.md + - [ ] Check \`three\` version bump (Needle uses \`@needle-tools/three\`) — any breaking changes? + - [ ] Update the \`reviewed-against\` stamp in SKILL.md when done: + \`\`\` + reviewed-against: "@needle-tools/engine@${LATEST}" + \`\`\` + - [ ] Close this issue once the skill is updated and stamp is committed + + --- + *Auto-generated by the [skill-review-check workflow](https://github.com/${{ github.repository }}/actions/workflows/skill-review-check.yml)* + BODY + )" + + echo "✅ Review issue created for v${LATEST}" + + - name: Summary + run: | + echo "## Skill Review Check Summary" >> $GITHUB_STEP_SUMMARY + echo "| | |" >> $GITHUB_STEP_SUMMARY + echo "|---|---|" >> $GITHUB_STEP_SUMMARY + echo "| Skill stamp | \`${{ steps.skill_version.outputs.stamp }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Latest npm | \`${{ steps.npm_version.outputs.latest }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| New version | ${{ steps.compare.outputs.new_version }} |" >> $GITHUB_STEP_SUMMARY diff --git a/providers/claude/plugin/skills/needle-engine/SKILL.md b/providers/claude/plugin/skills/needle-engine/SKILL.md index 7f201f9..b0034b6 100644 --- a/providers/claude/plugin/skills/needle-engine/SKILL.md +++ b/providers/claude/plugin/skills/needle-engine/SKILL.md @@ -1,6 +1,7 @@ --- name: needle-engine description: Automatically provides Needle Engine context when working in a Needle Engine web project. Use this skill when editing TypeScript components, Vite config, GLB assets, or anything related to @needle-tools/engine. +reviewed-against: "@needle-tools/engine@4.16.0" --- # Needle Engine @@ -129,6 +130,18 @@ export default defineConfig(async ({ command }) => ({ })); ``` +### `makeFilesLocal` — bundling all CDN dependencies + +Use the `makeFilesLocal` build option to download and bundle all CDN dependencies (Draco decoder, KTX2 transcoder, fonts, etc.) into the build output. This is essential for playable ads, app store submissions, and offline PWAs where external network requests are not allowed. + +```ts +// Auto-detect and download all CDN dependencies at build time: +needlePlugin({ makeFilesLocal: "auto" }) + +// Fine-grained control over which features to localize: +needlePlugin({ makeFilesLocal: { enabled: true, features: ["draco", "ktx2", "fonts"] } }) +``` + ## Deployment Projects can be deployed to: @@ -173,3 +186,8 @@ Use the `needle_search` MCP tool to find relevant docs, forum posts, and communi ## Common gotchas - Components must use `@registerType` or they won't be instantiated from GLB (this is handled automatically when exporting from Unity or Blender, but must be added manually for hand-written components) - GLB assets are in `assets/`, static files in `include/` or `public/` +- `showBalloonMessage` (since 4.16.0) accepts optional `duration`, `once`, and `key` options: + ```ts + showBalloonMessage("Hello!", { duration: 3, once: true, key: "my-message" }) + ``` + Use `once` + `key` to show a message only once per session even if called multiple times.