refactor: rename envVars to env and remove example field from TPMJS spec
- Rename TpmjsEnvVarSchema to TpmjsEnvSchema - Rename envVars field to env throughout codebase - Remove example field from TpmjsMinimalSchema (no longer required) - Update all documentation (spec page, publish page, HOW_TO_PUBLISH_A_TOOL.md) - Update example tool package.json - Simplify minimal tier requirements to only category and description 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
cd3dee8133
commit
013b98a53e
5 changed files with 48 additions and 83 deletions
|
|
@ -49,8 +49,7 @@ The bare minimum to get listed:
|
|||
{
|
||||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "A concise description of what your tool does",
|
||||
"example": "const result = await myTool({ input: 'hello' });"
|
||||
"description": "A concise description of what your tool does"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -58,7 +57,6 @@ The bare minimum to get listed:
|
|||
**Required fields:**
|
||||
- `category` - One of: `text-analysis`, `code-generation`, `data-processing`, `image-generation`, `audio-processing`, `search`, `integration`, `other`
|
||||
- `description` - Clear description of what the tool does (1-3 sentences)
|
||||
- `example` - Simple code example showing how to use the tool
|
||||
|
||||
#### Tier 2: Basic (Recommended)
|
||||
|
||||
|
|
@ -69,7 +67,6 @@ Add parameter and return type information:
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Analyzes sentiment in text and returns a score",
|
||||
"example": "const result = await analyzeSentiment({ text: 'I love this!' });",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
|
|
@ -102,7 +99,6 @@ Complete metadata for maximum visibility:
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Advanced sentiment analysis with emotion detection",
|
||||
"example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
|
|
@ -129,7 +125,7 @@ Complete metadata for maximum visibility:
|
|||
"type": "SentimentResult",
|
||||
"description": "Object with score, label, and optional emotions array"
|
||||
},
|
||||
"envVars": [
|
||||
"env": [
|
||||
{
|
||||
"name": "SENTIMENT_API_KEY",
|
||||
"description": "API key for sentiment analysis service",
|
||||
|
|
@ -266,7 +262,6 @@ Here's the complete `package.json` from the published example:
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
|
||||
"example": "const post = await createBlogPost({ title: 'My First Post', author: 'John Doe', content: 'Hello World!', tags: ['intro', 'blog'] });",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "title",
|
||||
|
|
@ -340,7 +335,6 @@ Here's the complete `package.json` from the published example:
|
|||
|-------|------|-------------|
|
||||
| `category` | string | Tool category (see categories below) |
|
||||
| `description` | string | Clear description (1-3 sentences) |
|
||||
| `example` | string | Code example showing usage |
|
||||
|
||||
### Optional Fields (Tier 2 - Basic)
|
||||
|
||||
|
|
@ -353,7 +347,7 @@ Here's the complete `package.json` from the published example:
|
|||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `envVars` | array | Required environment variables |
|
||||
| `env` | array | Required environment variables |
|
||||
| `frameworks` | array | Compatible frameworks |
|
||||
| `links` | object | Related URLs |
|
||||
| `tags` | array | Additional tags |
|
||||
|
|
@ -378,7 +372,7 @@ Choose one of these for the `category` field:
|
|||
If your tool requires environment variables:
|
||||
|
||||
```json
|
||||
"envVars": [
|
||||
"env": [
|
||||
{
|
||||
"name": "OPENAI_API_KEY",
|
||||
"description": "API key for OpenAI services",
|
||||
|
|
@ -426,7 +420,7 @@ Or manually check the structure matches the examples above.
|
|||
|
||||
**Tool not appearing after 15 minutes?**
|
||||
- Check that you added `"tpmjs-tool"` to keywords
|
||||
- Verify your `tpmjs` field has required fields (category, description, example)
|
||||
- Verify your `tpmjs` field has required fields (category, description)
|
||||
- Check the NPM package is public: `npm view yourpackage`
|
||||
|
||||
**Tool showing as "minimal" tier?**
|
||||
|
|
|
|||
|
|
@ -96,8 +96,7 @@ export default function PublishPage(): React.ReactElement {
|
|||
code={`{
|
||||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "A concise description of what your tool does",
|
||||
"example": "const result = await myTool({ input: 'hello' });"
|
||||
"description": "A concise description of what your tool does"
|
||||
}
|
||||
}`}
|
||||
/>
|
||||
|
|
@ -120,7 +119,6 @@ export default function PublishPage(): React.ReactElement {
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Analyzes sentiment in text",
|
||||
"example": "const result = await analyzeSentiment({ text: 'I love this!' });",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
|
|
@ -162,10 +160,9 @@ export default function PublishPage(): React.ReactElement {
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Advanced sentiment analysis with emotion detection",
|
||||
"example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
|
||||
"parameters": [...],
|
||||
"returns": {...},
|
||||
"envVars": [
|
||||
"env": [
|
||||
{
|
||||
"name": "SENTIMENT_API_KEY",
|
||||
"description": "API key for sentiment analysis service",
|
||||
|
|
@ -290,7 +287,6 @@ npm publish --access public
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Creates structured blog posts with frontmatter and SEO metadata",
|
||||
"example": "const post = await createBlogPost({ title: 'My Post', author: 'John', content: 'Hello' });",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "title",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { TPMJS_CATEGORIES } from '@tpmjs/types/tpmjs';
|
||||
import { Badge } from '@tpmjs/ui/Badge/Badge';
|
||||
import { Button } from '@tpmjs/ui/Button/Button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@tpmjs/ui/Card/Card';
|
||||
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
|
||||
import { Container } from '@tpmjs/ui/Container/Container';
|
||||
import { TPMJS_CATEGORIES } from '@tpmjs/types/tpmjs';
|
||||
import Link from 'next/link';
|
||||
import { AppHeader } from '~/components/AppHeader';
|
||||
|
||||
|
|
@ -49,8 +49,8 @@ export default function SpecPage(): React.ReactElement {
|
|||
specification for describing tool capabilities
|
||||
</li>
|
||||
<li>
|
||||
<strong className="text-foreground">Quality Scoring</strong> - Algorithmic
|
||||
ranking based on documentation completeness and community adoption
|
||||
<strong className="text-foreground">Quality Scoring</strong> - Algorithmic ranking
|
||||
based on documentation completeness and community adoption
|
||||
</li>
|
||||
<li>
|
||||
<strong className="text-foreground">AI Agent Integration</strong> - Structured
|
||||
|
|
@ -71,9 +71,11 @@ export default function SpecPage(): React.ReactElement {
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Add the <code className="text-foreground bg-surface px-1 rounded">tpmjs-tool</code> keyword
|
||||
and a <code className="text-foreground bg-surface px-1 rounded">tpmjs</code> metadata field
|
||||
to your package.json
|
||||
Add the{' '}
|
||||
<code className="text-foreground bg-surface px-1 rounded">tpmjs-tool</code>{' '}
|
||||
keyword and a{' '}
|
||||
<code className="text-foreground bg-surface px-1 rounded">tpmjs</code> metadata
|
||||
field to your package.json
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -110,9 +112,10 @@ export default function SpecPage(): React.ReactElement {
|
|||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">The Specification</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-8">
|
||||
The TPMJS specification defines a <code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs</code> field
|
||||
in package.json with three tiers of metadata. Higher tiers receive better visibility
|
||||
and quality scores.
|
||||
The TPMJS specification defines a{' '}
|
||||
<code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs</code> field in
|
||||
package.json with three tiers of metadata. Higher tiers receive better visibility and
|
||||
quality scores.
|
||||
</p>
|
||||
|
||||
{/* Tier 1: Minimal */}
|
||||
|
|
@ -151,16 +154,6 @@ export default function SpecPage(): React.ReactElement {
|
|||
appears in search results and tool listings.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-lg font-semibold text-foreground mb-2">
|
||||
<code>example</code> <span className="text-red-500">*</span>
|
||||
</h4>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Code example showing basic usage. Minimum 10 characters. Helps developers
|
||||
understand how to use your tool.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
|
|
@ -170,8 +163,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
code={`{
|
||||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Analyzes sentiment in text and returns positive/negative/neutral classification",
|
||||
"example": "const result = await analyzeSentiment({ text: 'I love this!' });"
|
||||
"description": "Analyzes sentiment in text and returns positive/negative/neutral classification"
|
||||
}
|
||||
}`}
|
||||
/>
|
||||
|
|
@ -246,7 +238,6 @@ export default function SpecPage(): React.ReactElement {
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Analyzes sentiment in text",
|
||||
"example": "const result = await analyzeSentiment({ text: 'I love this!' });",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
|
|
@ -289,7 +280,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
<div className="space-y-6">
|
||||
<div>
|
||||
<h4 className="text-lg font-semibold text-foreground mb-2">
|
||||
<code>envVars</code>
|
||||
<code>env</code>
|
||||
</h4>
|
||||
<p className="text-sm text-foreground-secondary mb-2">
|
||||
Array of environment variables required by the tool. Each variable has:
|
||||
|
|
@ -297,11 +288,11 @@ export default function SpecPage(): React.ReactElement {
|
|||
<ul className="list-disc list-inside space-y-1 text-sm text-foreground-secondary ml-4">
|
||||
<li>
|
||||
<code className="text-foreground">name</code> - Environment variable name
|
||||
(e.g., "OPENAI_API_KEY")
|
||||
(e.g., "OPENAI_API_KEY")
|
||||
</li>
|
||||
<li>
|
||||
<code className="text-foreground">description</code> - What the variable is
|
||||
used for
|
||||
<code className="text-foreground">description</code> - What the variable
|
||||
is used for
|
||||
</li>
|
||||
<li>
|
||||
<code className="text-foreground">required</code> - Boolean (defaults to
|
||||
|
|
@ -322,13 +313,17 @@ export default function SpecPage(): React.ReactElement {
|
|||
Array of compatible AI frameworks. Supported values:
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
{['vercel-ai', 'langchain', 'llamaindex', 'haystack', 'semantic-kernel'].map(
|
||||
(fw) => (
|
||||
<Badge key={fw} variant="outline" size="sm">
|
||||
{fw}
|
||||
</Badge>
|
||||
)
|
||||
)}
|
||||
{[
|
||||
'vercel-ai',
|
||||
'langchain',
|
||||
'llamaindex',
|
||||
'haystack',
|
||||
'semantic-kernel',
|
||||
].map((fw) => (
|
||||
<Badge key={fw} variant="outline" size="sm">
|
||||
{fw}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -417,10 +412,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Advanced sentiment analysis with emotion detection",
|
||||
"example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
|
||||
"parameters": [...],
|
||||
"returns": {...},
|
||||
"envVars": [
|
||||
"env": [
|
||||
{
|
||||
"name": "SENTIMENT_API_KEY",
|
||||
"description": "API key for sentiment analysis service",
|
||||
|
|
@ -499,21 +493,6 @@ export default function SpecPage(): React.ReactElement {
|
|||
</td>
|
||||
<td className="py-3 px-4">Tool description (20-500 chars)</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border">
|
||||
<td className="py-3 px-4">
|
||||
<code className="text-foreground">example</code>
|
||||
</td>
|
||||
<td className="py-3 px-4">string</td>
|
||||
<td className="py-3 px-4">
|
||||
<Badge variant="outline" size="sm">
|
||||
Minimal
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-red-500">Yes</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">Usage example code (min 10 chars)</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border">
|
||||
<td className="py-3 px-4">
|
||||
<code className="text-foreground">parameters</code>
|
||||
|
|
@ -542,7 +521,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
</tr>
|
||||
<tr className="border-b border-border">
|
||||
<td className="py-3 px-4">
|
||||
<code className="text-foreground">envVars</code>
|
||||
<code className="text-foreground">env</code>
|
||||
</td>
|
||||
<td className="py-3 px-4">array</td>
|
||||
<td className="py-3 px-4">
|
||||
|
|
@ -708,7 +687,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-foreground-secondary mb-2">
|
||||
Monitors NPM's real-time changes feed every 2 minutes
|
||||
Monitors NPM's real-time changes feed every 2 minutes
|
||||
</p>
|
||||
<Badge variant="outline" size="sm">
|
||||
Real-time
|
||||
|
|
@ -722,8 +701,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-foreground-secondary mb-2">
|
||||
Searches for <code className="text-foreground bg-surface px-1 rounded">tpmjs-tool</code> keyword
|
||||
every 15 minutes
|
||||
Searches for{' '}
|
||||
<code className="text-foreground bg-surface px-1 rounded">tpmjs-tool</code>{' '}
|
||||
keyword every 15 minutes
|
||||
</p>
|
||||
<Badge variant="outline" size="sm">
|
||||
Every 15 min
|
||||
|
|
@ -778,11 +758,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
Description must be 20-500 characters
|
||||
</li>
|
||||
<li>
|
||||
<strong className="text-foreground">Example too short:</strong> Example must be
|
||||
at least 10 characters
|
||||
</li>
|
||||
<li>
|
||||
<strong className="text-foreground">Invalid envVar:</strong> Each environment
|
||||
<strong className="text-foreground">Invalid env:</strong> Each environment
|
||||
variable must have a name and description
|
||||
</li>
|
||||
<li>
|
||||
|
|
@ -809,7 +785,8 @@ export default function SpecPage(): React.ReactElement {
|
|||
<CardContent className="pt-6 text-center">
|
||||
<div className="text-3xl mb-2">1️⃣</div>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Add <code className="text-foreground bg-surface px-1 rounded">tpmjs-tool</code> keyword
|
||||
Add <code className="text-foreground bg-surface px-1 rounded">tpmjs-tool</code>{' '}
|
||||
keyword
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
|
||||
"example": "const post = await createBlogPost({ title: 'My First Post', author: 'John Doe', content: 'Hello World!', tags: ['intro', 'blog'] });",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "title",
|
||||
|
|
|
|||
|
|
@ -46,14 +46,14 @@ export type TpmjsReturns = z.infer<typeof TpmjsReturnsSchema>;
|
|||
/**
|
||||
* Environment variable schema
|
||||
*/
|
||||
export const TpmjsEnvVarSchema = z.object({
|
||||
export const TpmjsEnvSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
description: z.string().min(1),
|
||||
required: z.boolean().default(true),
|
||||
default: z.string().optional(),
|
||||
});
|
||||
|
||||
export type TpmjsEnvVar = z.infer<typeof TpmjsEnvVarSchema>;
|
||||
export type TpmjsEnv = z.infer<typeof TpmjsEnvSchema>;
|
||||
|
||||
/**
|
||||
* External links schema
|
||||
|
|
@ -87,7 +87,6 @@ export const TpmjsMinimalSchema = z.object({
|
|||
message: `Category must be one of: ${TPMJS_CATEGORIES.join(', ')}`,
|
||||
}),
|
||||
description: z.string().min(20, 'Description must be at least 20 characters').max(500),
|
||||
example: z.string().min(10, 'Example must be at least 10 characters'),
|
||||
});
|
||||
|
||||
export type TpmjsMinimal = z.infer<typeof TpmjsMinimalSchema>;
|
||||
|
|
@ -99,7 +98,7 @@ export type TpmjsMinimal = z.infer<typeof TpmjsMinimalSchema>;
|
|||
export const TpmjsRichSchema = TpmjsMinimalSchema.extend({
|
||||
parameters: z.array(TpmjsParameterSchema).optional(),
|
||||
returns: TpmjsReturnsSchema.optional(),
|
||||
envVars: z.array(TpmjsEnvVarSchema).optional(),
|
||||
env: z.array(TpmjsEnvSchema).optional(),
|
||||
frameworks: z
|
||||
.array(z.enum(['vercel-ai', 'langchain', 'llamaindex', 'haystack', 'semantic-kernel']))
|
||||
.optional(),
|
||||
|
|
@ -138,7 +137,7 @@ export function validateTpmjsField(tpmjs: unknown): ValidationResult {
|
|||
const hasRichFields =
|
||||
data.parameters ||
|
||||
data.returns ||
|
||||
data.envVars ||
|
||||
data.env ||
|
||||
data.frameworks ||
|
||||
data.links ||
|
||||
data.tags ||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue