feat: add 5 research tools and blocks framework setup

- Add @tpmjs/tools-page-brief for URL content extraction
- Add @tpmjs/tools-compare-pages for cross-source validation
- Add @tpmjs/tools-source-credibility for credibility scoring
- Add @tpmjs/tools-claim-checklist for factual claim extraction
- Add @tpmjs/tools-timeline-from-text for timeline generation
- Move createBlogPost to packages/tools/official/
- Add blocks.yml for Blocks framework validation
- Update pnpm-workspace.yaml to include official tools
This commit is contained in:
Ajax Davis 2025-12-31 19:47:02 +10:00
parent 409d1232a6
commit 36a0735ab1
34 changed files with 2458 additions and 61 deletions

View file

@ -0,0 +1,13 @@
# @tpmjs/createblogpost
## 0.2.0
### Minor Changes
- Initial release of createBlogPost tool for TPMJS registry
- Creates structured blog posts with frontmatter and metadata
- Supports both Markdown and MDX formats
- Automatic slug generation, word count, and reading time calculation
- Rich TPMJS metadata including parameters, authentication, pricing, and AI agent guidance
- Tagged with 'tpmjs' keyword for NPM registry discovery

View file

@ -0,0 +1,107 @@
# @tpmjs/createblogpost
A tool for creating structured blog posts with frontmatter and metadata. Part of the TPMJS registry.
## Installation
```bash
npm install @tpmjs/createblogpost
# or
pnpm add @tpmjs/createblogpost
# or
yarn add @tpmjs/createblogpost
```
## Usage
```typescript
import { createBlogPost } from '@tpmjs/createblogpost';
const post = await createBlogPost({
title: 'Getting Started with TypeScript',
author: 'John Doe',
content: 'TypeScript is a typed superset of JavaScript that compiles to plain JavaScript...',
tags: ['typescript', 'javascript', 'programming'],
excerpt: 'Learn the basics of TypeScript in this comprehensive guide',
format: 'markdown',
});
console.log(post.formattedOutput);
```
## API
### `createBlogPost(options: BlogPostOptions): Promise<BlogPost>`
Creates a structured blog post with frontmatter and metadata.
#### Options
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `title` | `string` | Yes | - | The title of the blog post |
| `author` | `string` | Yes | - | The author of the blog post |
| `content` | `string` | Yes | - | The main content of the blog post |
| `tags` | `string[]` | No | `[]` | Array of tags for categorization |
| `format` | `'markdown' \| 'mdx'` | No | `'markdown'` | Output format for the blog post |
| `excerpt` | `string` | No | - | Short excerpt or summary of the post |
| `publishDate` | `Date` | No | `new Date()` | Publication date |
#### Returns
Returns a `BlogPost` object with the following structure:
```typescript
{
frontmatter: {
title: string;
author: string;
date: string; // ISO date format (YYYY-MM-DD)
tags: string[];
slug: string; // Auto-generated from title
wordCount: number; // Calculated from content
readingTime: number; // Estimated minutes to read
excerpt?: string;
};
content: string;
formattedOutput: string; // Complete post with frontmatter
}
```
## Example Output
```markdown
---
title: "Getting Started with TypeScript"
author: John Doe
date: 2025-11-28
slug: getting-started-with-typescript
tags: ["typescript", "javascript", "programming"]
excerpt: "Learn the basics of TypeScript in this comprehensive guide"
wordCount: 250
readingTime: 2
---
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript...
```
## Features
- Automatic slug generation from title
- Word count calculation
- Reading time estimation (200 words/min)
- Support for both Markdown and MDX formats
- Customizable frontmatter
- SEO-friendly metadata
## Use Cases
- Static site generators (Next.js, Gatsby, Astro)
- Content management systems
- Blog platforms
- Documentation sites
- Automated content generation
## License
MIT

View file

@ -0,0 +1,99 @@
{
"name": "@tpmjs/createblogpost",
"version": "0.3.0",
"description": "A tool for creating structured blog posts with AI-generated content",
"type": "module",
"keywords": ["tpmjs", "blog", "content", "ai", "writing"],
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"files": ["dist"],
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist .turbo"
},
"devDependencies": {
"@tpmjs/tsconfig": "workspace:*",
"tsup": "^8.3.5",
"typescript": "^5.9.3"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/ajaxdavis/tpmjs.git",
"directory": "packages/tools/official/createBlogPost"
},
"homepage": "https://tpmjs.com",
"license": "MIT",
"tpmjs": {
"category": "text-analysis",
"frameworks": ["vercel-ai"],
"tools": [
{
"exportName": "createBlogPostTool",
"description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
"parameters": [
{
"name": "title",
"type": "string",
"description": "The title of the blog post",
"required": true
},
{
"name": "author",
"type": "string",
"description": "The author of the blog post",
"required": true
},
{
"name": "content",
"type": "string",
"description": "The main content of the blog post",
"required": true
},
{
"name": "tags",
"type": "string[]",
"description": "Array of tags for categorization",
"required": false
},
{
"name": "format",
"type": "'markdown' | 'mdx'",
"description": "Output format for the blog post",
"required": false
},
{
"name": "excerpt",
"type": "string",
"description": "Short excerpt or summary of the post",
"required": false
}
],
"returns": {
"type": "BlogPost",
"description": "A structured blog post object with frontmatter, content, and metadata including slug, wordCount, readingTime, and formattedOutput"
},
"aiAgent": {
"useCase": "Use this tool when users need to generate blog posts, articles, or structured content with proper frontmatter and metadata. Ideal for content management systems, static site generators, and documentation sites.",
"limitations": "Does not include AI content generation - you must provide the content. Only formats and structures existing content.",
"examples": [
"Create a blog post about TypeScript best practices",
"Generate a tutorial post with code examples",
"Format an article with SEO metadata"
]
}
}
]
},
"dependencies": {
"ai": "6.0.0-beta.124"
}
}

View file

@ -0,0 +1,185 @@
/**
* Blog Post Creation Tool for TPMJS
* Creates structured blog posts with frontmatter and metadata
*
* This is a proper AI SDK v6 tool that can be used with streamText()
* Uses jsonSchema() to avoid Zod 4 JSON Schema conversion issues with OpenAI
*/
import { jsonSchema, tool } from 'ai';
export interface BlogPost {
frontmatter: {
title: string;
author: string;
date: string;
tags: string[];
excerpt?: string;
slug: string;
wordCount: number;
readingTime: number;
};
content: string;
formattedOutput: string;
}
/**
* Input type for Create Blog Post Tool
*/
type CreateBlogPostInput = {
title: string;
author: string;
content: string;
tags?: string[];
format?: 'markdown' | 'mdx';
excerpt?: string;
};
/**
* Creates a slug from a title
*/
function createSlug(title: string): string {
return title
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_-]+/g, '-')
.replace(/^-+|-+$/g, '');
}
/**
* Calculates reading time based on word count
* Assumes average reading speed of 200 words per minute
*/
function calculateReadingTime(wordCount: number): number {
return Math.ceil(wordCount / 200);
}
/**
* Counts words in content
*/
function countWords(content: string): number {
return content.trim().split(/\s+/).length;
}
/**
* Formats frontmatter as YAML
*/
function formatFrontmatter(
frontmatter: BlogPost['frontmatter'],
format: 'markdown' | 'mdx'
): string {
const delimiter = format === 'mdx' ? '---' : '---';
const lines = [
delimiter,
`title: "${frontmatter.title}"`,
`author: ${frontmatter.author}`,
`date: ${frontmatter.date}`,
`slug: ${frontmatter.slug}`,
`tags: [${frontmatter.tags.map((tag) => `"${tag}"`).join(', ')}]`,
];
if (frontmatter.excerpt) {
lines.push(`excerpt: "${frontmatter.excerpt}"`);
}
lines.push(`wordCount: ${frontmatter.wordCount}`);
lines.push(`readingTime: ${frontmatter.readingTime}`);
lines.push(delimiter);
return lines.join('\n');
}
/**
* Create Blog Post Tool
* Creates a structured blog post with frontmatter and metadata
*
* This is a proper AI SDK v6 tool that can be used with streamText()
*/
export const createBlogPostTool = tool({
description:
'Creates a structured blog post with frontmatter, metadata, slug, word count, and reading time. Outputs in Markdown or MDX format.',
inputSchema: jsonSchema<CreateBlogPostInput>({
type: 'object',
properties: {
title: {
type: 'string',
description: 'The title of the blog post',
},
author: {
type: 'string',
description: 'The author of the blog post',
},
content: {
type: 'string',
description: 'The main content of the blog post',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Array of tags for categorization',
},
format: {
type: 'string',
enum: ['markdown', 'mdx'],
description: 'Output format for the blog post (default: markdown)',
},
excerpt: {
type: 'string',
description: 'Short excerpt or summary of the post',
},
},
required: ['title', 'author', 'content'],
additionalProperties: false,
}),
async execute({ title, author, content, tags = [], format = 'markdown', excerpt }) {
// Validate required fields
if (!title || title.trim().length === 0) {
throw new Error('Title is required');
}
if (!author || author.trim().length === 0) {
throw new Error('Author is required');
}
if (!content || content.trim().length === 0) {
throw new Error('Content is required');
}
// Calculate metadata
const slug = createSlug(title);
const wordCount = countWords(content);
const readingTime = calculateReadingTime(wordCount);
const publishDate = new Date();
// Build frontmatter
const frontmatter: BlogPost['frontmatter'] = {
title,
author,
date: publishDate.toISOString().split('T')[0] || '',
tags,
slug,
wordCount,
readingTime,
};
if (excerpt) {
frontmatter.excerpt = excerpt;
}
// Format the complete blog post
const formattedFrontmatter = formatFrontmatter(frontmatter, format);
const formattedOutput = `${formattedFrontmatter}\n\n${content}`;
return {
frontmatter,
content,
formattedOutput,
};
},
});
/**
* Export default for convenience
*/
export default createBlogPostTool;

View file

@ -0,0 +1,11 @@
{
"extends": "@tpmjs/tsconfig/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"incremental": false,
"composite": false
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,10 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
treeshake: true,
splitting: false,
});