feat: add 100+ official TPMJS tools

Implements a comprehensive suite of AI SDK v6 tools across multiple categories:

- Research (5): page-brief, compare-pages, source-credibility, claim-checklist, timeline-from-text
- Web (10): fetch-text, links-catalog, extract-meta, extract-json-ld, redirect-trace, sitemap-read, rss-read, table-extract, robots-policy, url-normalize
- Data (15): csv-parse, csv-stringify, json-repair, json-schema-validate, yaml-parse, yaml-stringify, text-chunk, normalize-whitespace, dedupe-by-key, pivot, rows-filter, rows-sort, rows-group-aggregate, rows-join, schema-infer
- Doc (12): toc-generate, glossary-build, faq-from-text, executive-brief, decision-record-adr, prd-outline, acceptance-criteria, style-rewrite
- Eng (12): diff-text-unified, env-var-docs-generate, dependency-audit-lite, conventional-commit-suggest, markdown-lint-basic, test-case-generate, stacktrace-parse, release-notes, changelog-entry, release-checklist
- Security (7): redact-secrets, secret-scan-text, url-risk-heuristic, csp-compose, hardening-checklist-web, access-control-matrix, data-classification-heuristic
- Stats (9): effect-size-suite, bootstrap-ci, permutation-test, multiple-testing-adjust, linear-regression-ols, logistic-regression, time-series-decompose-lite, anomaly-detect-mad
- Ops (7): slo-draft, runbook-draft, postmortem-draft, postmortem-action-extractor, error-log-triage, coverage-tracker, monitoring-gap-analysis
- Agent (15): prompt-to-workflow-skeleton, workflow-validate-io, workflow-explain, workflow-cost-estimate, tool-call-accuracy-score, eval-fixture-build, guardrail-policy-draft, workflow-auto-repair, tool-selection-plan, novelty-score-workflow, workflow-variant-generate, config-normalize, recipe-*
- Utility (8): base64-encode, base64-decode, hash-text, regex-extract, template-render, date-parse, json-path-query, url-parse
- HTML (3): html-sanitize, html-to-markdown, markdown-to-html

All tools follow AI SDK v6 pattern with tool() and jsonSchema<T>().

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-12-31 22:55:56 +10:00
parent 2d9b06020d
commit 5d2096fb5d
499 changed files with 50782 additions and 238 deletions

View file

@ -0,0 +1,196 @@
# @tpmjs/tools-csv-stringify
Convert array of objects to CSV string using [papaparse](https://www.papaparse.com/).
## Installation
```bash
npm install @tpmjs/tools-csv-stringify
# or
pnpm add @tpmjs/tools-csv-stringify
# or
yarn add @tpmjs/tools-csv-stringify
```
## Usage
### With Vercel AI SDK
```typescript
import { csvStringifyTool } from '@tpmjs/tools-csv-stringify';
import { generateText } from 'ai';
const result = await generateText({
model: yourModel,
tools: {
csvStringify: csvStringifyTool,
},
prompt: 'Convert this data to CSV format: [{"name":"Alice","age":25},{"name":"Bob","age":30}]',
});
```
### Direct Usage
```typescript
import { csvStringifyTool } from '@tpmjs/tools-csv-stringify';
const result = await csvStringifyTool.execute({
rows: [
{ name: 'Alice', age: 25, city: 'New York' },
{ name: 'Bob', age: 30, city: 'San Francisco' },
{ name: 'Charlie', age: 35, city: 'Boston' },
],
});
console.log(result.csv);
// name,age,city
// Alice,25,New York
// Bob,30,San Francisco
// Charlie,35,Boston
console.log(result);
// {
// csv: '...',
// rowCount: 3,
// metadata: {
// headers: ['name', 'age', 'city'],
// stringifiedAt: '2025-01-15T12:00:00.000Z',
// byteSize: 85
// }
// }
```
## Features
- **Automatic Header Detection** - Uses object keys from first row if headers not provided
- **Custom Headers** - Optionally specify custom header names and order
- **Type Preservation** - Properly handles strings, numbers, booleans, and null values
- **Standards Compliant** - Follows RFC 4180 CSV specification
- **Byte Size Reporting** - Returns UTF-8 byte size for file writing
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `rows` | `Record<string, unknown>[]` | Yes | - | Array of objects to convert to CSV |
| `headers` | `string[]` | No | Object keys from first row | Custom header names |
## Returns
```typescript
{
csv: string;
rowCount: number;
metadata: {
headers: string[];
stringifiedAt: string;
byteSize: number;
};
}
```
## Examples
### Basic Usage
```typescript
const result = await csvStringifyTool.execute({
rows: [
{ product: 'Laptop', price: 999.99, inStock: true },
{ product: 'Mouse', price: 29.99, inStock: false },
],
});
console.log(result.csv);
// product,price,inStock
// Laptop,999.99,true
// Mouse,29.99,false
```
### Custom Headers
```typescript
const result = await csvStringifyTool.execute({
rows: [
{ name: 'Alice', age: 25, city: 'NYC' },
{ name: 'Bob', age: 30, city: 'SF' },
],
headers: ['name', 'city'], // Only include these columns
});
console.log(result.csv);
// name,city
// Alice,NYC
// Bob,SF
```
### Custom Header Order
```typescript
const result = await csvStringifyTool.execute({
rows: [
{ age: 25, name: 'Alice', city: 'NYC' },
{ age: 30, name: 'Bob', city: 'SF' },
],
headers: ['name', 'age', 'city'], // Specify order
});
console.log(result.csv);
// name,age,city
// Alice,25,NYC
// Bob,30,SF
```
### Handling Special Characters
```typescript
const result = await csvStringifyTool.execute({
rows: [
{ name: 'Alice, Jr.', message: 'Hello "World"' },
{ name: 'Bob\nSmith', message: 'Line\nBreak' },
],
});
// Properly escapes commas, quotes, and newlines
console.log(result.csv);
// name,message
// "Alice, Jr.","Hello ""World"""
// "Bob\nSmith","Line\nBreak"
```
### Writing to File
```typescript
import { writeFile } from 'fs/promises';
const result = await csvStringifyTool.execute({
rows: [...],
});
await writeFile('output.csv', result.csv, 'utf-8');
console.log(`Wrote ${result.metadata.byteSize} bytes to output.csv`);
```
## Error Handling
```typescript
try {
const result = await csvStringifyTool.execute({
rows: [],
});
} catch (error) {
console.error(error.message); // "Rows array cannot be empty"
}
try {
const result = await csvStringifyTool.execute({
rows: ['not', 'objects'], // Invalid
});
} catch (error) {
console.error(error.message); // "All rows must be objects"
}
```
## License
MIT

View file

@ -0,0 +1,68 @@
{
"name": "@tpmjs/tools-csv-stringify",
"version": "0.1.0",
"description": "Convert array of objects to CSV string using papaparse",
"type": "module",
"keywords": ["tpmjs", "data", "csv", "stringify"],
"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:*",
"@types/papaparse": "^5.3.15",
"tsup": "^8.3.5",
"typescript": "^5.9.3"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/anthropics/tpmjs.git",
"directory": "packages/tools/official/csv-stringify"
},
"homepage": "https://tpmjs.com",
"license": "MIT",
"tpmjs": {
"category": "data",
"frameworks": ["vercel-ai"],
"tools": [
{
"name": "csvStringifyTool",
"description": "Convert array of objects to CSV string with optional custom headers",
"parameters": [
{
"name": "rows",
"type": "array",
"description": "Array of objects to convert to CSV",
"required": true
},
{
"name": "headers",
"type": "array",
"description": "Optional array of header names (default: uses object keys)",
"required": false
}
],
"returns": {
"type": "CsvStringifyResult",
"description": "Object with csv string and rowCount"
}
}
]
},
"dependencies": {
"ai": "6.0.0-beta.124",
"papaparse": "^5.4.1"
}
}

View file

@ -0,0 +1,124 @@
/**
* CSV Stringify Tool for TPMJS
* Converts array of objects to CSV string using papaparse
*
* @requires Node.js 18+
*/
import { jsonSchema, tool } from 'ai';
import Papa from 'papaparse';
/**
* Output interface for CSV stringification
*/
export interface CsvStringifyResult {
csv: string;
rowCount: number;
metadata: {
headers: string[];
stringifiedAt: string;
byteSize: number;
};
}
type CsvStringifyInput = {
rows: Record<string, unknown>[];
headers?: string[];
};
/**
* CSV Stringify Tool
* Converts array of objects to CSV format with optional custom headers
*/
export const csvStringifyTool = tool({
description:
'Convert an array of objects to CSV string format. Optionally specify custom headers. Returns the CSV string, row count, and metadata. Useful for exporting data to CSV files or API responses.',
inputSchema: jsonSchema<CsvStringifyInput>({
type: 'object',
properties: {
rows: {
type: 'array',
description: 'Array of objects to convert to CSV',
items: {
type: 'object',
additionalProperties: true,
},
},
headers: {
type: 'array',
description:
'Optional array of header names. If not provided, uses object keys from first row.',
items: {
type: 'string',
},
},
},
required: ['rows'],
additionalProperties: false,
}),
async execute({ rows, headers }): Promise<CsvStringifyResult> {
// Validate input
if (!rows || !Array.isArray(rows)) {
throw new Error('Rows must be an array');
}
if (rows.length === 0) {
throw new Error('Rows array cannot be empty');
}
// Validate that all rows are objects
if (!rows.every((row) => typeof row === 'object' && row !== null && !Array.isArray(row))) {
throw new Error('All rows must be objects (not arrays or primitives)');
}
// Determine headers
let actualHeaders: string[];
if (headers && headers.length > 0) {
// Validate custom headers
if (!Array.isArray(headers)) {
throw new Error('Headers must be an array of strings');
}
if (!headers.every((h) => typeof h === 'string')) {
throw new Error('All headers must be strings');
}
actualHeaders = headers;
} else {
// Extract headers from first row
const firstRow = rows[0];
if (!firstRow) {
throw new Error('Cannot determine headers from empty first row');
}
actualHeaders = Object.keys(firstRow);
}
if (actualHeaders.length === 0) {
throw new Error('No headers found. Either provide headers or ensure rows have properties.');
}
// Convert to CSV using papaparse
const csv = Papa.unparse(rows, {
columns: actualHeaders,
header: true,
skipEmptyLines: false,
newline: '\n',
});
// Calculate byte size
const byteSize = new TextEncoder().encode(csv).length;
// Build result
const result: CsvStringifyResult = {
csv,
rowCount: rows.length,
metadata: {
headers: actualHeaders,
stringifiedAt: new Date().toISOString(),
byteSize,
},
};
return result;
},
});
export default csvStringifyTool;

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,
});