Skip to content

fix(icons): use icon exports in ejected skins #430

fix(icons): use icon exports in ejected skins

fix(icons): use icon exports in ejected skins #430

name: API Reference Sync
on:
pull_request:
types: [closed]
permissions:
actions: read
contents: write
pull-requests: write
issues: write
id-token: write
concurrency:
group: api-reference-sync-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
# ─── Job 0: Build API JSON at HEAD~1 and HEAD, diff them ─────────────
analyze:
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
outputs:
has_diff: ${{ steps.classify.outputs.has_diff }}
has_new: ${{ steps.classify.outputs.has_new }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version-file: '.nvmrc'
cache: pnpm
- name: Collect PR metadata
id: meta
env:
PR_TITLE: ${{ github.event.pull_request.title || 'manual run' }}
run: |
mkdir -p /tmp/api-sync
jq -n \
--arg number "${{ github.event.pull_request.number || '' }}" \
--arg url "${{ github.event.pull_request.html_url || '' }}" \
--arg author "${{ github.event.pull_request.user.login || '' }}" \
--arg title "$PR_TITLE" \
'{number: $number, url: $url, author: $author, title: $title}' \
> /tmp/api-sync/pr-meta.json
cat /tmp/api-sync/pr-meta.json
- name: Build API JSON at HEAD
run: |
pnpm install --frozen-lockfile
pnpm -C site api-docs
mkdir -p /tmp/api-sync/after-components /tmp/api-sync/after-utils
cp -r site/src/content/generated-component-reference/* /tmp/api-sync/after-components/ 2>/dev/null || true
cp -r site/src/content/generated-util-reference/* /tmp/api-sync/after-utils/ 2>/dev/null || true
- name: Build API JSON at HEAD~1
run: |
git checkout HEAD~1
# If install or build fails (e.g. api-docs-builder itself changed),
# treat everything as new by leaving before dirs empty
mkdir -p /tmp/api-sync/before-components /tmp/api-sync/before-utils
if pnpm install --frozen-lockfile && pnpm -C site api-docs; then
cp -r site/src/content/generated-component-reference/* /tmp/api-sync/before-components/ 2>/dev/null || true
cp -r site/src/content/generated-util-reference/* /tmp/api-sync/before-utils/ 2>/dev/null || true
else
echo "::warning::HEAD~1 build failed — treating all components/utils as new"
fi
git checkout -
- name: Classify changes
id: classify
run: |
# Unified diff of both JSON directories
diff -ruN /tmp/api-sync/before-components /tmp/api-sync/after-components > /tmp/api-sync/diff.patch || true
diff -ruN /tmp/api-sync/before-utils /tmp/api-sync/after-utils >> /tmp/api-sync/diff.patch || true
# New: files in after but not in before
comm -23 \
<(ls /tmp/api-sync/after-components/ 2>/dev/null | sort) \
<(ls /tmp/api-sync/before-components/ 2>/dev/null | sort) \
> /tmp/api-sync/new-components.txt
comm -23 \
<(ls /tmp/api-sync/after-utils/ 2>/dev/null | sort) \
<(ls /tmp/api-sync/before-utils/ 2>/dev/null | sort) \
> /tmp/api-sync/new-utils.txt
# Changed: files in both, but content differs
comm -12 \
<(ls /tmp/api-sync/after-components/ 2>/dev/null | sort) \
<(ls /tmp/api-sync/before-components/ 2>/dev/null | sort) \
| while read -r f; do
if ! diff -q "/tmp/api-sync/before-components/$f" "/tmp/api-sync/after-components/$f" >/dev/null 2>&1; then
echo "$f"
fi
done > /tmp/api-sync/changed-components.txt
comm -12 \
<(ls /tmp/api-sync/after-utils/ 2>/dev/null | sort) \
<(ls /tmp/api-sync/before-utils/ 2>/dev/null | sort) \
| while read -r f; do
if ! diff -q "/tmp/api-sync/before-utils/$f" "/tmp/api-sync/after-utils/$f" >/dev/null 2>&1; then
echo "$f"
fi
done > /tmp/api-sync/changed-utils.txt
# Log results
echo "=== New components ===" && cat /tmp/api-sync/new-components.txt
echo "=== New utils ===" && cat /tmp/api-sync/new-utils.txt
echo "=== Changed components ===" && cat /tmp/api-sync/changed-components.txt
echo "=== Changed utils ===" && cat /tmp/api-sync/changed-utils.txt
echo "=== Diff ===" && head -100 /tmp/api-sync/diff.patch
# Set outputs
if [ -s /tmp/api-sync/diff.patch ]; then
echo "has_diff=true" >> "$GITHUB_OUTPUT"
else
echo "has_diff=false" >> "$GITHUB_OUTPUT"
fi
if [ -s /tmp/api-sync/new-components.txt ] || [ -s /tmp/api-sync/new-utils.txt ]; then
echo "has_new=true" >> "$GITHUB_OUTPUT"
else
echo "has_new=false" >> "$GITHUB_OUTPUT"
fi
- name: Upload artifact
if: steps.classify.outputs.has_diff == 'true'
uses: actions/upload-artifact@v4
with:
name: api-diff
path: /tmp/api-sync/
retention-days: 1
# ─── Job 1: Open issues for new components/utils without reference pages
new-references:
needs: analyze
if: needs.analyze.outputs.has_new == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: api-diff
path: /tmp/api-sync
- name: Open issues for missing reference pages
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
PR_NUMBER=$(jq -r .number /tmp/api-sync/pr-meta.json)
PR_URL=$(jq -r .url /tmp/api-sync/pr-meta.json)
PR_AUTHOR=$(jq -r .author /tmp/api-sync/pr-meta.json)
REF_DIR="site/src/content/docs/reference"
# --- New components ---
if [ -s /tmp/api-sync/new-components.txt ]; then
while read -r filename; do
JSON_PATH="/tmp/api-sync/after-components/$filename"
NAME=$(jq -r .name "$JSON_PATH")
SLUG="${filename%.json}"
# Check if a reference page already uses this component
if grep -rq "<ComponentReference component=\"$NAME\"" "$REF_DIR/"; then
echo "Reference exists for component $NAME — skipping"
continue
fi
# Check for existing open issue (dedup by drift-type + component name)
EXISTING=$(gh issue list \
--label "docs" \
--search "docs(reference): add $NAME API reference page" \
--state open \
--json number \
--jq 'length')
if [ "$EXISTING" -gt 0 ]; then
echo "Open issue already exists for $NAME — skipping"
continue
fi
ASSIGNEE_FLAG=""
if [ -n "$PR_AUTHOR" ]; then
ASSIGNEE_FLAG="--assignee $PR_AUTHOR"
fi
BODY="$(cat <<EOF
<!-- drift-type:new-reference -->
<!-- trigger-pr:$PR_NUMBER -->
<!-- component:$NAME -->
## New Component: \`$NAME\`
A new component \`$NAME\` was added in #${PR_NUMBER} but has no API reference page yet.
### What's needed
- [ ] Create reference page with anatomy, prose, demos, and \`<ComponentReference component="$NAME" />\`
- [ ] Add sidebar entry in \`site/src/docs.config.ts\`
- [ ] Verify build: \`pnpm -C site build\`
### Context
- Triggering PR: $PR_URL
- Generated JSON: \`site/src/content/generated-component-reference/$filename\`
> Use the \`/api-reference $SLUG\` skill to scaffold this page.
EOF
)"
gh issue create \
--title "docs(reference): add $NAME API reference page" \
--body "$BODY" \
--label "docs,site,components" \
$ASSIGNEE_FLAG
echo "Created issue for component $NAME"
done < /tmp/api-sync/new-components.txt
fi
# --- New utils ---
if [ -s /tmp/api-sync/new-utils.txt ]; then
while read -r filename; do
JSON_PATH="/tmp/api-sync/after-utils/$filename"
NAME=$(jq -r .name "$JSON_PATH")
SLUG="${filename%.json}"
# Check if a reference page already uses this util
if grep -rq "<UtilReference util=\"$NAME\"" "$REF_DIR/"; then
echo "Reference exists for util $NAME — skipping"
continue
fi
# Check for existing open issue
EXISTING=$(gh issue list \
--label "docs" \
--search "docs(reference): add $NAME API reference page" \
--state open \
--json number \
--jq 'length')
if [ "$EXISTING" -gt 0 ]; then
echo "Open issue already exists for $NAME — skipping"
continue
fi
ASSIGNEE_FLAG=""
if [ -n "$PR_AUTHOR" ]; then
ASSIGNEE_FLAG="--assignee $PR_AUTHOR"
fi
BODY="$(cat <<EOF
<!-- drift-type:new-reference -->
<!-- trigger-pr:$PR_NUMBER -->
<!-- util:$NAME -->
## New Utility: \`$NAME\`
A new utility \`$NAME\` was added in #${PR_NUMBER} but has no API reference page yet.
### What's needed
- [ ] Create reference page with usage examples and \`<UtilReference util="$NAME" />\`
- [ ] Add sidebar entry in \`site/src/docs.config.ts\`
- [ ] Verify build: \`pnpm -C site build\`
### Context
- Triggering PR: $PR_URL
- Generated JSON: \`site/src/content/generated-util-reference/$filename\`
> Use the \`/api-reference $SLUG\` skill to scaffold this page.
EOF
)"
gh issue create \
--title "docs(reference): add $NAME API reference page" \
--body "$BODY" \
--label "docs,site" \
$ASSIGNEE_FLAG
echo "Created issue for util $NAME"
done < /tmp/api-sync/new-utils.txt
fi
# ─── Job 2: Detect stale docs (Claude Opus) ─────────────────────────
stale-docs:
needs: analyze
if: needs.analyze.outputs.has_diff == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: api-diff
path: /tmp/api-sync
- name: Detect stale docs
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: |
--model opus
--max-turns 25
--allowedTools "Read" "Glob" "Grep" "Bash(gh:*)" "Bash(cat:*)" "Bash(jq:*)" "Bash(diff:*)" "Bash(ls:*)" "Bash(head:*)" "Bash(tail:*)" "Bash(wc:*)" "Bash(sort:*)"
prompt: |
You are the stale-docs detection agent. Your job: given a pre-computed API diff,
find documentation that may need updating and open ONE GitHub issue summarizing all findings.
## Inputs
The following files are at /tmp/api-sync/:
- `diff.patch` — unified diff of API JSON between HEAD~1 and HEAD
- `changed-components.txt` — filenames of changed component JSONs (one per line, may be empty)
- `changed-utils.txt` — filenames of changed util JSONs (one per line, may be empty)
- `after-components/` — current component JSON files
- `after-utils/` — current util JSON files
- `pr-meta.json` — `{number, url, author, title}` of the triggering PR
Important: Focus on items in `changed-components.txt` and `changed-utils.txt`.
Skip any components/utils listed in `new-components.txt` or `new-utils.txt` —
a separate job already opens issues for those.
## Process
Step 1: Read `pr-meta.json` and `diff.patch`. Understand what API surfaces changed and how.
Step 2: For each changed component/util, read the "after" JSON to understand the current API shape.
Step 3: Search for documentation that references these APIs. Check ALL of:
- `site/src/content/docs/reference/` — MDX reference pages (look for stale prop descriptions,
missing new props/state/data-attributes, outdated type signatures)
- `site/src/content/docs/concepts/` — concept pages mentioning these APIs
- `site/src/content/docs/how-to/` — how-to guides mentioning these APIs
- `site/src/components/docs/demos/` — demo code using changed props/state/signatures
- `packages/*/README.md` — package READMEs mentioning these APIs
Use Grep and Glob to search efficiently. Look for:
- The component/util name (PascalCase, camelCase)
- Specific prop/state/parameter names that were added, removed, or changed in the diff
- HTML element names from `platforms.html.tagName` in the JSON (e.g. `media-play-button`)
- Data attribute names that changed
Step 4: For each file with hits, read the relevant section and assess:
- `high` — definitely stale (references a removed/renamed prop by old name, shows old signature)
- `medium` — likely stale (mentions API whose behavior/type changed)
- `low` — possibly stale (mentions the component but may not be affected)
Discard clear false positives. Include borderline cases for human review.
Step 5: If you found ANY stale references, open exactly ONE issue using `gh issue create`.
If you found NOTHING stale, do NOT create an issue — just output "No stale docs detected."
## Issue format
Read `pr-meta.json` to get PR_NUMBER, PR_URL, PR_AUTHOR, and PR_TITLE.
Assign the issue to the PR author: `--assignee $PR_AUTHOR` (skip if author is empty).
Title: `docs(site): stale docs from #$PR_NUMBER`
Labels: `docs,site`
Body (use this structure exactly):
```
<!-- drift-type:stale-docs -->
<!-- trigger-pr:{PR_NUMBER} -->
## Summary
API changes in #{PR_NUMBER} ({PR_TITLE}) may have made the following documentation stale.
## Triggering PR
{PR_URL}
## API Changes
{Brief summary of what changed in the API — new props, removed props, type changes, etc.}
## Stale Documentation Found
### High Confidence
| File | Line(s) | Issue | API Change |
|---|---|---|---|
{rows or "None found"}
### Medium Confidence
| File | Line(s) | Issue | API Change |
|---|---|---|---|
{rows or "None found"}
### Low Confidence
| File | Line(s) | Issue | API Change |
|---|---|---|---|
{rows or "None found"}
## Recommended Actions
{Bulleted list of specific things to fix}
```
## Rules
- Open at most ONE issue per run. Group everything into one issue.
- Do NOT create or modify any files. Do NOT create PRs. Issues only.
- Do NOT open an issue if there is nothing stale.
- Before creating an issue, check for existing open issues that have BOTH
`<!-- drift-type:stale-docs -->` and `<!-- trigger-pr:{PR_NUMBER} -->` in their body.
If one exists, skip creation to avoid duplicates.
- Be thorough but efficient — use Grep to find files, then Read only relevant sections.