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,117 @@
# @tpmjs/tools-stacktrace-parse
Parses stack traces into structured frames, handling Node.js and browser formats.
## Installation
```bash
npm install @tpmjs/tools-stacktrace-parse
```
## Usage
```typescript
import { stacktraceParse } from '@tpmjs/tools-stacktrace-parse';
import { generateText } from 'ai';
const result = await generateText({
model: yourModel,
tools: {
stacktraceParse,
},
prompt: 'Parse this stack trace and tell me where the error occurred',
});
```
## Tool Details
### stacktraceParse
Parses a stack trace string into structured frames with file, method name, line number, and column information.
**Parameters:**
- `stacktrace` (string, required) - The stack trace string to parse (from Node.js or browser)
**Returns:**
```typescript
{
frames: Array<{
file: string | null;
methodName: string | null;
lineNumber: number | null;
column: number | null;
arguments: string[];
}>;
errorType: string | null; // e.g., "TypeError", "ReferenceError"
errorMessage: string | null; // The error message
language: 'node' | 'browser' | 'unknown';
totalFrames: number;
summary: string;
}
```
## Example Output
Given this stack trace:
```
TypeError: Cannot read property 'foo' of undefined
at getUserData (/app/user.js:45:12)
at processRequest (/app/server.js:123:5)
at Server.handleRequest (/app/server.js:89:3)
```
Returns:
```typescript
{
frames: [
{
file: "/app/user.js",
methodName: "getUserData",
lineNumber: 45,
column: 12,
arguments: []
},
{
file: "/app/server.js",
methodName: "processRequest",
lineNumber: 123,
column: 5,
arguments: []
},
{
file: "/app/server.js",
methodName: "Server.handleRequest",
lineNumber: 89,
column: 3,
arguments: []
}
],
errorType: "TypeError",
errorMessage: "Cannot read property 'foo' of undefined",
language: "node",
totalFrames: 3,
summary: "TypeError - Cannot read property 'foo' of undefined - 3 frames"
}
```
## Features
- Parses Node.js and browser stack traces
- Extracts error type and message
- Provides structured frame information
- Detects stack trace format (Node.js vs browser)
- Handles various stack trace formats
## Supported Formats
- **Node.js**: Standard V8 stack traces
- **Browser**: Chrome, Firefox, Safari formats
- **Webpack**: Bundled stack traces with source maps
## License
MIT

View file

@ -0,0 +1,61 @@
{
"name": "@tpmjs/tools-stacktrace-parse",
"version": "0.1.0",
"description": "Parses stack traces into structured frames, handling Node.js and browser formats",
"type": "module",
"keywords": ["tpmjs", "engineering", "stacktrace", "error", "debugging"],
"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/anthropics/tpmjs.git",
"directory": "packages/tools/official/stacktrace-parse"
},
"homepage": "https://tpmjs.com",
"license": "MIT",
"tpmjs": {
"category": "engineering",
"frameworks": ["vercel-ai"],
"tools": [
{
"name": "stacktraceParse",
"description": "Parses stack traces into structured frames, handling Node.js and browser formats",
"parameters": [
{
"name": "stacktrace",
"type": "string",
"description": "The stack trace string to parse",
"required": true
}
],
"returns": {
"type": "StackTraceResult",
"description": "Object with parsed frames, error type, error message, and detected language"
}
}
]
},
"dependencies": {
"ai": "6.0.0-beta.124",
"stacktrace-parser": "^0.1.10"
}
}

View file

@ -0,0 +1,201 @@
/**
* Stacktrace Parse Tool for TPMJS
* Parses stack traces into structured frames, handling Node.js and browser formats
*/
import { jsonSchema, tool } from 'ai';
import { parse as parseStacktrace } from 'stacktrace-parser';
/**
* Represents a single frame in the stack trace
*/
export interface StackFrame {
file: string | null;
methodName: string | null;
lineNumber: number | null;
column: number | null;
arguments: string[];
}
/**
* Output interface for the parsed stack trace
*/
export interface StackTraceResult {
frames: StackFrame[];
errorType: string | null;
errorMessage: string | null;
language: 'node' | 'browser' | 'unknown';
totalFrames: number;
summary: string;
}
type StackTraceParseInput = {
stacktrace: string;
};
/**
* Detects the error type and message from the stack trace
*/
function extractErrorInfo(stacktrace: string): {
errorType: string | null;
errorMessage: string | null;
} {
const lines = stacktrace.trim().split('\n');
if (lines.length === 0) {
return { errorType: null, errorMessage: null };
}
const firstLine = lines[0]?.trim();
if (!firstLine) {
return { errorType: null, errorMessage: null };
}
// Common error format: "ErrorType: Error message"
const errorMatch = firstLine.match(/^(\w+Error):\s*(.+)$/);
if (errorMatch) {
return {
errorType: errorMatch[1] ?? null,
errorMessage: errorMatch[2] ?? null,
};
}
// Just error type: "ErrorType"
if (/^\w+Error$/.test(firstLine)) {
return {
errorType: firstLine,
errorMessage: null,
};
}
// Generic format with colon
const colonMatch = firstLine.match(/^([^:]+):\s*(.+)$/);
if (colonMatch) {
return {
errorType: colonMatch[1] ?? null,
errorMessage: colonMatch[2] ?? null,
};
}
// Fallback: treat entire first line as message
return {
errorType: null,
errorMessage: firstLine,
};
}
/**
* Detects whether the stack trace is from Node.js or browser
*/
function detectLanguage(stacktrace: string): 'node' | 'browser' | 'unknown' {
// Node.js indicators
if (
/at\s+\w+\s+\([^)]+\)/.test(stacktrace) &&
(/node_modules/.test(stacktrace) ||
/internal\//.test(stacktrace) ||
/\.js:\d+:\d+/.test(stacktrace))
) {
return 'node';
}
// Browser indicators
if (
/https?:\/\//.test(stacktrace) ||
/@https?:\/\//.test(stacktrace) ||
/webpack:\/\//.test(stacktrace)
) {
return 'browser';
}
// Check for typical Node.js patterns
if (/at\s+\w+/.test(stacktrace) && /:\d+:\d+/.test(stacktrace)) {
return 'node';
}
return 'unknown';
}
/**
* Stacktrace Parse Tool
* Parses stack traces into structured frames
*/
export const stacktraceParse = tool({
description:
'Parses a stack trace string into structured frames with file, method name, line number, and column information. Handles both Node.js and browser stack trace formats. Useful for analyzing errors and debugging issues.',
inputSchema: jsonSchema<StackTraceParseInput>({
type: 'object',
properties: {
stacktrace: {
type: 'string',
description: 'The stack trace string to parse (from Node.js or browser)',
},
},
required: ['stacktrace'],
additionalProperties: false,
}),
async execute({ stacktrace }): Promise<StackTraceResult> {
// Validate input
if (typeof stacktrace !== 'string') {
throw new Error('stacktrace must be a string');
}
if (stacktrace.trim().length === 0) {
throw new Error('stacktrace cannot be empty');
}
// Extract error information
const { errorType, errorMessage } = extractErrorInfo(stacktrace);
// Detect language/environment
const language = detectLanguage(stacktrace);
// Parse the stack trace
let parsedFrames: Array<{
file: string | null;
methodName: string | null;
lineNumber: number | null;
column: number | null;
arguments?: string[];
}>;
try {
parsedFrames = parseStacktrace(stacktrace);
} catch (error) {
throw new Error(
`Failed to parse stack trace: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
// Convert to our frame format
const frames: StackFrame[] = parsedFrames.map((frame) => ({
file: frame.file || null,
methodName: frame.methodName || null,
lineNumber:
frame.lineNumber !== undefined && frame.lineNumber !== null ? frame.lineNumber : null,
column: frame.column !== undefined && frame.column !== null ? frame.column : null,
arguments: frame.arguments || [],
}));
// Create summary
let summary: string;
if (frames.length === 0) {
summary = 'No stack frames parsed';
} else {
const parts: string[] = [];
if (errorType) parts.push(errorType);
if (errorMessage) parts.push(errorMessage);
parts.push(`${frames.length} frame${frames.length !== 1 ? 's' : ''}`);
summary = parts.join(' - ');
}
return {
frames,
errorType,
errorMessage,
language,
totalFrames: frames.length,
summary,
};
},
});
export default stacktraceParse;

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