feat(scripts): follow metadata instructions for described use-cases

Load the Use Cases section of .github/instructions/metadata.instructions.md
into the --describe prompt so generated use-cases match the repository
style, and make useCase an array of phrases per usage group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q2D9GYbnSV56MAVVhHPRhH
This commit is contained in:
Claude
2026-10-09 09:46:01 +00:00
parent fba5e3f3cc
commit 6983a6a175
3 changed files with 47 additions and 11 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ pnpm icon-usage --icons-file exports.txt --describe --max-contexts 30
`--context` extracts how each icon is used in every validated file: what kind of usage it is (a JSX/template element, a prop such as `icon={Trash2}`, a config object such as `{ title: 'Settings', icon: Settings }`, or a `data-lucide` attribute), the parent elements (for example `DropdownMenuItem` or `Button`), the enclosing component, label text (`aria-label`, `title`, visible text, i18n keys like `t('actions.delete')`), event handlers, links, and a short code snippet. Each usage gets a heuristic description such as `Trash2 in <DropdownMenuItem> labelled "Delete Project" within NavProjects`. Each icon gets a summary of the most common labels, parents and handlers, plus example links to the exact lines on GitHub.
`--describe` does the same, then sends the collected contexts to an OpenAI model (`OPENAI_API_KEY` required; `--model` or `OPENAI_MODEL` selects the model, `gpt-5-mini` by default). The model groups them into several use cases per icon, each with a short lowercase `useCase` phrase in the style of the `use-cases` field in `icons/*.json`, a description of where the icon appears in the UI, its approximate share of the sample, and example links. The icon's existing `use-cases` are included in the prompt. Responses are cached in the cache directory.
`--describe` does the same, then sends the collected contexts to an OpenAI model (`OPENAI_API_KEY` required; `--model` or `OPENAI_MODEL` selects the model, `gpt-5-mini` by default). The model groups them into 1 to 4 use cases per icon. Each has a `useCase` array of 1 to 3 phrases for the `use-cases` field in `icons/*.json`, written following the "Use Cases" section of `.github/instructions/metadata.instructions.md` (loaded into the prompt at runtime), a description of where the icon appears in the UI, its approximate share of the sample, and example links. The icon's existing `use-cases` are included in the prompt. Responses are cached in the cache directory.
Use `--output <file>` (or `-o`) to write the results per icon to a JSON file shaped as `{ [icon]: [...usage] }`. With `--describe`, each entry is a use case (`useCase`, `description`, `sampleShare`, `examples`). Without it, each entry is an individual usage (`description`, `repository`, `url`, `kind`, `parents`, `component`, `labels`, `handlers`, `links`). `--output` implies `--context`, and the normal terminal, `--json` or `--csv` output is still printed.
+1 -1
View File
@@ -1445,7 +1445,7 @@ const printUsage = (usage: Record<string, IconUsage>) => {
console.log(' use cases:');
for (const description of descriptions) {
console.log(
` - ${description.useCase} (~${formatPercent(description.sampleShare * 100)})`,
` - ${description.useCase.join(' / ')} (~${formatPercent(description.sampleShare * 100)})`,
);
console.log(` ${description.description}`);
for (const example of description.examples) console.log(` ${example}`);
+45 -9
View File
@@ -514,7 +514,7 @@ export const summarizeContexts = (matches: ContextMatch[]): IconContextSummary =
};
export type UsageDescription = {
useCase: string;
useCase: string[];
description: string;
sampleShare: number;
examples: string[];
@@ -531,6 +531,33 @@ type DescribeOptions = {
writeCache: (key: string, value: UsageDescription[]) => Promise<void>;
};
const METADATA_INSTRUCTIONS = new URL(
'../.github/instructions/metadata.instructions.md',
import.meta.url,
);
const FALLBACK_USE_CASE_GUIDELINES = `Write each use-case as a short phrase of roughly 4-12 words starting with a present participle verb (e.g. "Indicating a low battery charge level"), from the interface's perspective, naming the concrete context where useful. No trailing period, no first person, no marketing language, and never just the icon's name.`;
/**
* Returns the "Use Cases" section of the repository's metadata instructions
* (including its examples), so generated use-cases follow the same style.
*/
const loadUseCaseGuidelines = async () => {
try {
const fs = await import('node:fs/promises');
const instructions = await fs.readFile(METADATA_INSTRUCTIONS, 'utf8');
const start = instructions.indexOf('## Use Cases');
if (start === -1) return FALLBACK_USE_CASE_GUIDELINES;
const sections = instructions.slice(start).split(/\n(?=## )/);
return sections
.filter((section, index) => index === 0 || section.startsWith('## Examples'))
.join('\n')
.trim();
} catch {
return FALLBACK_USE_CASE_GUIDELINES;
}
};
/**
* Asks an OpenAI model to cluster the collected usage contexts into distinct,
* real-world use cases for the icon. Responses are cached by prompt hash.
@@ -560,15 +587,24 @@ export const describeIconUsage = async ({
const input = `You are maintaining the metadata for the Lucide icon library. Below are real usages of the \`${icon}\` icon found in public GitHub repositories, extracted from source code.
Group these usages into distinct use cases and describe each one.
Group these usages by what the icon means in them, and describe each group.
Guidelines:
- useCase: short lowercase phrase describing the concrete situation the icon represents (e.g. "deleting an item from a list"). No trailing punctuation. Match the style of the existing use-cases if any.
Fields for each group:
- useCase: an array of 1-3 use-case phrases for this group, written exactly as the use-case guidelines below describe. Add more than one phrase only when the group covers genuinely distinct uses; never rephrase the same idea. Don't repeat a phrase across groups.
- description: one or two sentences describing how and where the icon appears in the UI (e.g. inside a ghost button in a table row, next to a "Delete" label).
- sampleShare: the approximate fraction (0-1) of the samples that belong to this use case.
- examples: ids of up to 3 samples that best illustrate the use case.
- Return between 1 and 8 use cases, most common first. Ignore samples without enough context to judge.
- Base everything on the samples; do not invent use cases that are not supported by them.
- sampleShare: the approximate fraction (0-1) of the samples that belong to this group.
- examples: ids of up to 3 samples that best illustrate the group.
Rules:
- Return between 1 and 4 groups, most common first. Ignore samples without enough context to judge.
- The samples are your source material: extract the function the icon serves in the interface and discard implementation details such as component names, class names or file paths.
- Base everything on the samples; never invent use cases that are not supported by them.
- Match the style of the existing use-cases, and avoid duplicating them.
Use-case guidelines (from .github/instructions/metadata.instructions.md):
<guidelines>
${await loadUseCaseGuidelines()}
</guidelines>
Existing use-cases for "${icon}": ${JSON.stringify(existingUseCases)}
@@ -591,7 +627,7 @@ ${JSON.stringify(samples, null, 1)}`;
const schema = z.object({
useCases: z.array(
z.object({
useCase: z.string(),
useCase: z.array(z.string()),
description: z.string(),
sampleShare: z.number(),
examples: z.array(z.number()),