diff --git a/apps/playground/next-env.d.ts b/apps/playground/next-env.d.ts
index c4b7818..9edff1c 100644
--- a/apps/playground/next-env.d.ts
+++ b/apps/playground/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/dev/types/routes.d.ts";
+import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts
index c4b7818..9edff1c 100644
--- a/apps/web/next-env.d.ts
+++ b/apps/web/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/dev/types/routes.d.ts";
+import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/packages/tools/create-basic-tools/.changeset/README.md b/packages/tools/create-basic-tools/.changeset/README.md
new file mode 100644
index 0000000..e5b6d8d
--- /dev/null
+++ b/packages/tools/create-basic-tools/.changeset/README.md
@@ -0,0 +1,8 @@
+# Changesets
+
+Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
+with multi-package repos, or single-package repos to help you version and publish your code. You can
+find the full documentation for it [in our repository](https://github.com/changesets/changesets)
+
+We have a quick list of common questions to get you started engaging with this project in
+[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
diff --git a/packages/tools/create-basic-tools/.changeset/config.json b/packages/tools/create-basic-tools/.changeset/config.json
new file mode 100644
index 0000000..d88011f
--- /dev/null
+++ b/packages/tools/create-basic-tools/.changeset/config.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
+ "changelog": "@changesets/cli/changelog",
+ "commit": false,
+ "fixed": [],
+ "linked": [],
+ "access": "restricted",
+ "baseBranch": "main",
+ "updateInternalDependencies": "patch",
+ "ignore": []
+}
diff --git a/packages/tools/create-basic-tools/CHANGELOG.md b/packages/tools/create-basic-tools/CHANGELOG.md
new file mode 100644
index 0000000..e1b8d61
--- /dev/null
+++ b/packages/tools/create-basic-tools/CHANGELOG.md
@@ -0,0 +1,17 @@
+# @tpmjs/create-basic-tools
+
+## 1.0.0
+
+### Major Changes
+
+- Initial release of @tpmjs/create-basic-tools - CLI generator for scaffolding production-ready TPMJS tool packages
+
+ Features:
+
+ - Interactive CLI with beautiful prompts using @clack/prompts
+ - Generates packages with minimum 2 tools (ideally 2-3)
+ - Zod 4 schemas - uses Zod directly (not jsonSchema wrapper)
+ - One file per tool in src/tools/.ts
+ - TPMJS validated against official schemas from @tpmjs/types
+ - Complete package generation ready to publish to npm
+ - Works both standalone and in monorepo packages/ folders
diff --git a/packages/tools/create-basic-tools/README.md b/packages/tools/create-basic-tools/README.md
new file mode 100644
index 0000000..b172518
--- /dev/null
+++ b/packages/tools/create-basic-tools/README.md
@@ -0,0 +1,200 @@
+# @tpmjs/create-basic-tools
+
+CLI generator for scaffolding production-ready TPMJS tool packages with 2-3 tools by default.
+
+## Features
+
+- 🎯 **Multi-tool packages**: Generates packages with minimum 2 tools (ideally 2-3)
+- 🔧 **Zod 4 schemas**: Uses Zod directly (not jsonSchema wrapper)
+- ⚡ **AI SDK v6**: Full compatibility with the latest AI SDK
+- 📦 **One file per tool**: Clean `src/tools/.ts` structure
+- ✅ **TPMJS validated**: Auto-validates against official TPMJS schemas
+- 🎨 **Beautiful CLI**: Interactive prompts with @clack/prompts
+- 📝 **Complete setup**: Generates package.json, tsconfig, tsup config, README, and more
+- 🚀 **Publish ready**: Generated packages are ready to publish to npm immediately
+
+## Usage
+
+### Interactive Mode (Recommended)
+
+```bash
+pnpmx @tpmjs/create-basic-tools
+```
+
+This will guide you through an interactive wizard that asks:
+
+1. **Package info**: name, description, author, license
+2. **Tool definitions**: At least 2 tools (export name + description)
+3. **Category**: Choose from 12 TPMJS categories
+4. **Mode**: Simple (basic Zod schemas) or Advanced (full control)
+5. **Output path**: Where to create the package
+6. **Confirmation**: Review and confirm
+
+### Example Session
+
+```bash
+$ pnpmx @tpmjs/create-basic-tools
+
+┌ create-tpmjs-tool
+│
+◇ Package name
+│ @myorg/content-tools
+│
+◇ Package description
+│ AI SDK tools for content processing
+│
+◇ Tool #1 export name
+│ summarizeText
+│
+◇ Tool #1 description
+│ Summarize a block of text into a concise overview.
+│
+◇ Tool #2 export name
+│ extractKeywords
+│
+◇ Tool #2 description
+│ Extract important keywords from text.
+│
+◇ Add tool #3? (already have 2)
+│ Yes
+│
+◇ Tool #3 export name
+│ classifySentiment
+│
+◇ Tool #3 description
+│ Classify the sentiment of text as positive, negative, or neutral.
+│
+◇ Category
+│ text-analysis
+│
+◇ Mode
+│ Simple Mode - Basic Zod schemas
+│
+◇ Where should we create the package?
+│ ./content-tools
+│
+◇ Ready to generate?
+│ Yes
+│
+└ Success! Created @myorg/content-tools at ./content-tools
+```
+
+## Generated Package Structure
+
+```
+content-tools/
+├── src/
+│ ├── tools/ # One file per tool
+│ │ ├── summarizeText.ts
+│ │ ├── extractKeywords.ts
+│ │ └── classifySentiment.ts
+│ └── index.ts # Re-exports all tools
+├── dist/ # Build output (after pnpm build)
+│ ├── index.js
+│ └── index.d.ts
+├── package.json # With complete tpmjs field
+├── tsconfig.json
+├── tsup.config.ts
+├── README.md
+├── .gitignore
+├── .npmignore
+└── LICENSE
+```
+
+## Generated Tool File Example
+
+Each tool file follows this Zod-first pattern:
+
+```typescript
+import { tool } from 'ai';
+import { z } from 'zod';
+
+const SummarizeTextSchema = z.object({
+ text: z.string().min(1, 'Text cannot be empty').describe('The input text to process.'),
+ options: z.object({
+ language: z.string().default('en').describe('Language code (e.g., en, es, fr).'),
+ maxLength: z.number().int().positive().default(100).describe('Maximum length of output.'),
+ }).default({ language: 'en', maxLength: 100 }).describe('Optional configuration.'),
+});
+
+export const summarizeText = tool({
+ description: 'Summarize a block of text into a concise overview.',
+ inputSchema: SummarizeTextSchema,
+ async execute(input: z.infer) {
+ // TODO: Implement the tool logic here
+ console.log('summarizeText called with:', input);
+
+ return {
+ success: true,
+ message: 'Tool executed successfully. Replace this with your implementation.',
+ input,
+ };
+ },
+});
+```
+
+## After Generation
+
+Once the package is generated:
+
+```bash
+cd content-tools
+
+# Install dependencies
+pnpm install
+
+# Build the package
+pnpm build
+
+# Type-check
+pnpm type-check
+
+# Publish to npm
+pnpm publish --access public
+```
+
+Your tools will appear on [tpmjs.com](https://tpmjs.com) within 2-15 minutes after publishing!
+
+## TPMJS Categories
+
+The generator validates against these official TPMJS categories:
+
+- `web-scraping`
+- `data-processing`
+- `file-operations`
+- `communication`
+- `database`
+- `api-integration`
+- `image-processing`
+- `text-analysis`
+- `automation`
+- `ai-ml`
+- `security`
+- `monitoring`
+
+## Requirements
+
+- Node.js 18+
+- pnpm (recommended)
+
+## Development
+
+This is a generator package itself. To work on it:
+
+```bash
+# Install dependencies
+pnpm install
+
+# Build
+pnpm build
+
+# Type-check
+pnpm type-check
+
+# Test locally
+node dist/index.js
+```
+
+## License
+
+MIT
diff --git a/packages/tools/create-basic-tools/package.json b/packages/tools/create-basic-tools/package.json
new file mode 100644
index 0000000..476dff1
--- /dev/null
+++ b/packages/tools/create-basic-tools/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "@tpmjs/create-basic-tools",
+ "version": "1.0.0",
+ "description": "CLI generator for scaffolding production-ready TPMJS tool packages",
+ "type": "module",
+ "bin": {
+ "create-basic-tools": "./dist/index.js"
+ },
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "tsup",
+ "dev": "tsup --watch",
+ "type-check": "tsc --noEmit"
+ },
+ "keywords": ["tpmjs", "ai-sdk", "generator", "cli", "scaffold", "boilerplate"],
+ "dependencies": {
+ "@clack/prompts": "^0.7.0",
+ "commander": "^14.0.0",
+ "picocolors": "^1.0.0",
+ "validate-npm-package-name": "^5.0.0",
+ "zod": "^4.1.13"
+ },
+ "devDependencies": {
+ "@tpmjs/tsconfig": "workspace:*",
+ "@tpmjs/types": "workspace:*",
+ "@types/validate-npm-package-name": "^4.0.2",
+ "tsup": "^8.3.5",
+ "typescript": "^5.9.3"
+ },
+ "files": ["dist", "templates", "README.md"]
+}
diff --git a/packages/tools/create-basic-tools/src/cli.ts b/packages/tools/create-basic-tools/src/cli.ts
new file mode 100644
index 0000000..27bca3b
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/cli.ts
@@ -0,0 +1,180 @@
+import * as path from 'node:path';
+import * as clack from '@clack/prompts';
+import { generateTsConfig, generateTsupConfig } from './generators/config-files.js';
+import { generatePackageJson } from './generators/package-json.js';
+import { generateReadme } from './generators/readme.js';
+import { generateIndexFile, generateToolFile } from './generators/source-code.js';
+import { promptCategoryAndMode, promptConfirmation, promptOutputPath } from './prompts/advanced.js';
+import { promptBasicInfo } from './prompts/basic.js';
+import { promptTools } from './prompts/tools.js';
+import type { GenerationResult, GeneratorConfig } from './types.js';
+import {
+ copyTemplate,
+ ensureDir,
+ getAbsolutePath,
+ pathExists,
+ writeFile,
+} from './utils/file-writer.js';
+import * as logger from './utils/logger.js';
+
+/**
+ * Runs the interactive CLI workflow
+ */
+export async function runInteractiveCLI(): Promise {
+ clack.intro(logger.bold('create-tpmjs-tool'));
+
+ // Step 1: Get basic package info
+ const packageInfo = await promptBasicInfo();
+ if (!packageInfo) {
+ clack.cancel('Operation cancelled');
+ process.exit(0);
+ }
+
+ // Step 2: Get tool definitions (minimum 2)
+ const tools = await promptTools();
+ if (!tools || tools.length < 2) {
+ clack.cancel('Operation cancelled');
+ process.exit(0);
+ }
+
+ // Step 3: Get category and mode
+ const categoryAndMode = await promptCategoryAndMode();
+
+ if (!categoryAndMode) {
+ clack.cancel('Operation cancelled');
+ process.exit(0);
+ }
+
+ packageInfo.category = categoryAndMode.category;
+
+ // Step 4: Get output path
+ const packageNameWithoutScope = packageInfo.name.split('/').pop() || packageInfo.name;
+ const defaultPath = `./${packageNameWithoutScope}`;
+
+ const outputPath = await promptOutputPath(defaultPath);
+ if (!outputPath) {
+ clack.cancel('Operation cancelled');
+ process.exit(0);
+ }
+
+ const absoluteOutputPath = getAbsolutePath(outputPath);
+
+ // Check if directory exists
+ if (await pathExists(absoluteOutputPath)) {
+ clack.log.error(`Directory already exists: ${absoluteOutputPath}`);
+ clack.cancel('Operation cancelled');
+ process.exit(1);
+ }
+
+ // Step 5: Confirm generation
+ const confirmed = await promptConfirmation(packageInfo.name, tools.length, outputPath);
+ if (!confirmed) {
+ clack.cancel('Operation cancelled');
+ process.exit(0);
+ }
+
+ // Step 6: Generate the package
+ const spinner = clack.spinner();
+ spinner.start('Generating package...');
+
+ const config: GeneratorConfig = {
+ packageInfo,
+ tools,
+ outputPath: absoluteOutputPath,
+ mode: categoryAndMode.mode,
+ };
+
+ try {
+ const result = await generatePackage(config);
+
+ spinner.stop('Package generated successfully!');
+
+ clack.outro(`
+${logger.green('✓')} Success! Created ${logger.bold(packageInfo.name)} at ${logger.cyan(outputPath)}
+
+ Files created:
+${result.filesCreated.map((f) => ` ${f}`).join('\n')}
+
+ Next steps:
+ ${logger.cyan(`cd ${outputPath}`)}
+ ${logger.cyan('pnpm install')}
+ ${logger.cyan('pnpm build')}
+ ${logger.cyan('pnpm type-check')}
+ ${logger.cyan('pnpm publish')}
+`);
+
+ return result;
+ } catch (error) {
+ spinner.stop('Generation failed');
+ clack.log.error(error instanceof Error ? error.message : 'Unknown error occurred');
+ clack.cancel('Operation failed');
+ process.exit(1);
+ }
+}
+
+/**
+ * Generates the package files
+ */
+async function generatePackage(config: GeneratorConfig): Promise {
+ const { packageInfo, tools, outputPath } = config;
+ const filesCreated: string[] = [];
+
+ // Create directory structure
+ await ensureDir(outputPath);
+ await ensureDir(path.join(outputPath, 'src'));
+ await ensureDir(path.join(outputPath, 'src', 'tools'));
+
+ // Generate package.json
+ const packageJsonPath = path.join(outputPath, 'package.json');
+ await writeFile(packageJsonPath, generatePackageJson(config));
+ filesCreated.push('package.json');
+
+ // Generate tool files
+ for (const tool of tools) {
+ const toolPath = path.join(outputPath, 'src', 'tools', `${tool.exportName}.ts`);
+ await writeFile(toolPath, generateToolFile(tool));
+ filesCreated.push(`src/tools/${tool.exportName}.ts`);
+ }
+
+ // Generate index.ts
+ const indexPath = path.join(outputPath, 'src', 'index.ts');
+ await writeFile(indexPath, generateIndexFile(tools));
+ filesCreated.push('src/index.ts');
+
+ // Generate tsconfig.json
+ const tsconfigPath = path.join(outputPath, 'tsconfig.json');
+ await writeFile(tsconfigPath, generateTsConfig());
+ filesCreated.push('tsconfig.json');
+
+ // Generate tsup.config.ts
+ const tsupConfigPath = path.join(outputPath, 'tsup.config.ts');
+ await writeFile(tsupConfigPath, generateTsupConfig());
+ filesCreated.push('tsup.config.ts');
+
+ // Generate README.md
+ const readmePath = path.join(outputPath, 'README.md');
+ await writeFile(readmePath, generateReadme(config));
+ filesCreated.push('README.md');
+
+ // Copy static templates
+ const gitignorePath = path.join(outputPath, '.gitignore');
+ await copyTemplate('gitignore.txt', gitignorePath);
+ filesCreated.push('.gitignore');
+
+ const npmignorePath = path.join(outputPath, '.npmignore');
+ await copyTemplate('npmignore.txt', npmignorePath);
+ filesCreated.push('.npmignore');
+
+ const licensePath = path.join(outputPath, 'LICENSE');
+ await copyTemplate('license-mit.txt', licensePath, {
+ YEAR: new Date().getFullYear().toString(),
+ AUTHOR: packageInfo.author || 'Author Name',
+ });
+ filesCreated.push('LICENSE');
+
+ return {
+ success: true,
+ outputPath,
+ filesCreated,
+ };
+}
diff --git a/packages/tools/create-basic-tools/src/generators/config-files.ts b/packages/tools/create-basic-tools/src/generators/config-files.ts
new file mode 100644
index 0000000..577bf7c
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/generators/config-files.ts
@@ -0,0 +1,45 @@
+/**
+ * Generates tsconfig.json content
+ */
+export function generateTsConfig(): string {
+ const config = {
+ compilerOptions: {
+ target: 'ES2022',
+ module: 'ESNext',
+ moduleResolution: 'bundler',
+ lib: ['ES2022'],
+ outDir: './dist',
+ rootDir: './src',
+ declaration: true,
+ declarationMap: true,
+ sourceMap: true,
+ strict: true,
+ esModuleInterop: true,
+ skipLibCheck: true,
+ forceConsistentCasingInFileNames: true,
+ resolveJsonModule: true,
+ allowSyntheticDefaultImports: true,
+ },
+ include: ['src/**/*'],
+ exclude: ['node_modules', 'dist'],
+ };
+
+ return JSON.stringify(config, null, 2);
+}
+
+/**
+ * Generates tsup.config.ts content
+ */
+export function generateTsupConfig(): string {
+ return `import { defineConfig } from 'tsup';
+
+export default defineConfig({
+ entry: ['src/index.ts'],
+ format: ['esm'],
+ dts: true,
+ clean: true,
+ treeshake: true,
+ splitting: false,
+});
+`;
+}
diff --git a/packages/tools/create-basic-tools/src/generators/package-json.ts b/packages/tools/create-basic-tools/src/generators/package-json.ts
new file mode 100644
index 0000000..0ddbde7
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/generators/package-json.ts
@@ -0,0 +1,52 @@
+import type { GeneratorConfig } from '../types.js';
+
+/**
+ * Generates the package.json content for a TPMJS tool package
+ */
+export function generatePackageJson(config: GeneratorConfig): string {
+ const { packageInfo, tools } = config;
+
+ const pkg = {
+ name: packageInfo.name,
+ version: '0.0.1',
+ description: packageInfo.description,
+ type: 'module',
+ main: 'dist/index.js',
+ types: 'dist/index.d.ts',
+ scripts: {
+ build: 'tsup',
+ dev: 'tsup --watch',
+ 'type-check': 'tsc --noEmit',
+ },
+ keywords: ['tpmjs-tool', 'ai-sdk', packageInfo.category],
+ author: packageInfo.author || '',
+ license: packageInfo.license,
+ tpmjs: {
+ category: packageInfo.category,
+ tools: tools.map((tool) => ({
+ exportName: tool.exportName,
+ description: tool.description,
+ ...(tool.parameters && { parameters: tool.parameters }),
+ ...(tool.returns && { returns: tool.returns }),
+ ...(tool.aiAgent && { aiAgent: tool.aiAgent }),
+ })),
+ ...(tools.some((t) => t.env) && {
+ env: tools.flatMap((t) => t.env || []),
+ }),
+ ...(tools.some((t) => t.frameworks) && {
+ frameworks: Array.from(new Set(tools.flatMap((t) => t.frameworks || []))),
+ }),
+ },
+ dependencies: {
+ ai: '^6.0.0',
+ zod: '^4.1.13',
+ },
+ devDependencies: {
+ tsup: '^8.3.5',
+ typescript: '^5.9.3',
+ },
+ files: ['dist', 'README.md'],
+ };
+
+ return JSON.stringify(pkg, null, 2);
+}
diff --git a/packages/tools/create-basic-tools/src/generators/readme.ts b/packages/tools/create-basic-tools/src/generators/readme.ts
new file mode 100644
index 0000000..f9ac3fc
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/generators/readme.ts
@@ -0,0 +1,77 @@
+import type { GeneratorConfig } from '../types.js';
+
+/**
+ * Generates README.md content for the tool package
+ */
+export function generateReadme(config: GeneratorConfig): string {
+ const { packageInfo, tools } = config;
+
+ const toolsList = tools.map((tool) => `- **${tool.exportName}**: ${tool.description}`).join('\n');
+
+ const usageExample = tools[0];
+ if (!usageExample) {
+ throw new Error('At least one tool is required');
+ }
+
+ return `# ${packageInfo.name}
+
+${packageInfo.description}
+
+## Installation
+
+\`\`\`bash
+pnpm add ${packageInfo.name}
+\`\`\`
+
+## Tools
+
+This package provides ${tools.length} tool${tools.length > 1 ? 's' : ''} for the AI SDK:
+
+${toolsList}
+
+## Usage
+
+\`\`\`typescript
+import { ${usageExample.exportName} } from '${packageInfo.name}';
+import { generateText } from 'ai';
+import { openai } from '@ai-sdk/openai';
+
+const result = await generateText({
+ model: openai('gpt-4'),
+ prompt: 'Process this text for me',
+ tools: {
+ ${usageExample.exportName},
+ },
+});
+
+console.log(result.text);
+\`\`\`
+
+## Development
+
+\`\`\`bash
+# Install dependencies
+pnpm install
+
+# Build the package
+pnpm build
+
+# Type-check
+pnpm type-check
+
+# Watch mode
+pnpm dev
+\`\`\`
+
+## Publishing
+
+1. Update the version in \`package.json\`
+2. Build the package: \`pnpm build\`
+3. Publish to npm: \`pnpm publish --access public\`
+4. Your tools will appear on [tpmjs.com](https://tpmjs.com) within 2-15 minutes
+
+## License
+
+${packageInfo.license}
+`;
+}
diff --git a/packages/tools/create-basic-tools/src/generators/source-code.ts b/packages/tools/create-basic-tools/src/generators/source-code.ts
new file mode 100644
index 0000000..7f5d556
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/generators/source-code.ts
@@ -0,0 +1,65 @@
+import type { ToolDefinition } from '../types.js';
+
+/**
+ * Generates a single tool file with Zod schema
+ */
+export function generateToolFile(tool: ToolDefinition): string {
+ const { exportName, description } = tool;
+
+ // Generate schema name (capitalize first letter + "Schema")
+ const schemaName = `${exportName.charAt(0).toUpperCase()}${exportName.slice(1)}Schema`;
+
+ // Generate simple Zod schema (can be enhanced in advanced mode)
+ const schemaContent = generateSimpleSchema();
+
+ return `import { tool } from 'ai';
+import { z } from 'zod';
+
+const ${schemaName} = z.object({
+${schemaContent}
+});
+
+export const ${exportName} = tool({
+ description: '${description}',
+ inputSchema: ${schemaName},
+ async execute(input: z.infer) {
+ // TODO: Implement the tool logic here
+ console.log('${exportName} called with:', input);
+
+ return {
+ success: true,
+ message: 'Tool executed successfully. Replace this with your implementation.',
+ input,
+ };
+ },
+});
+`;
+}
+
+/**
+ * Generates a simple Zod schema with example fields
+ */
+function generateSimpleSchema(): string {
+ return ` text: z.string().min(1, 'Text cannot be empty').describe('The input text to process.'),
+ options: z.object({
+ language: z.string().default('en').describe('Language code (e.g., en, es, fr).'),
+ maxLength: z.number().int().positive().default(100).describe('Maximum length of output.'),
+ }).default({ language: 'en', maxLength: 100 }).describe('Optional configuration.'),`;
+}
+
+/**
+ * Generates the main index.ts file that re-exports all tools
+ */
+export function generateIndexFile(tools: ToolDefinition[]): string {
+ const exports = tools
+ .map((tool) => `export { ${tool.exportName} } from './tools/${tool.exportName}.js';`)
+ .join('\n');
+
+ return `/**
+ * TPMJS Tool Package
+ * Auto-generated by @tpmjs/create-basic-tools
+ */
+
+${exports}
+`;
+}
diff --git a/packages/tools/create-basic-tools/src/index.ts b/packages/tools/create-basic-tools/src/index.ts
new file mode 100644
index 0000000..1289219
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/index.ts
@@ -0,0 +1,30 @@
+#!/usr/bin/env node
+
+import { Command } from 'commander';
+import { runInteractiveCLI } from './cli.js';
+
+const program = new Command();
+
+program
+ .name('create-basic-tools')
+ .description('CLI generator for scaffolding production-ready TPMJS tool packages')
+ .version('0.0.1')
+ .option('--name ', 'Package name (e.g., @myorg/content-tools)')
+ .option('--description ', 'Package description')
+ .option('--category ', 'Tool category')
+ .option('--tool ', 'Tool definition (format: "exportName:description")')
+ .option('--output ', 'Output path')
+ .option('--yes', 'Skip confirmation prompt')
+ .action(async (options) => {
+ // For now, only support interactive mode
+ // CLI flags mode can be added later
+ if (options.name || options.description || options.category || options.tool) {
+ console.log('CLI flags mode is not yet implemented.');
+ console.log('Please run without flags for interactive mode.');
+ process.exit(1);
+ }
+
+ await runInteractiveCLI();
+ });
+
+program.parse();
diff --git a/packages/tools/create-basic-tools/src/prompts/advanced.ts b/packages/tools/create-basic-tools/src/prompts/advanced.ts
new file mode 100644
index 0000000..d44beff
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/prompts/advanced.ts
@@ -0,0 +1,91 @@
+import * as clack from '@clack/prompts';
+import { getAvailableCategories } from '../validation/tool-metadata.js';
+
+/**
+ * Prompts for category and mode selection
+ */
+export async function promptCategoryAndMode(): Promise<{
+ category: string;
+ mode: 'simple' | 'advanced';
+} | null> {
+ const categories = getAvailableCategories();
+
+ const category = await clack.select({
+ message: 'Tool category',
+ options: categories.map((cat) => ({
+ value: cat,
+ label: cat,
+ })),
+ });
+
+ if (clack.isCancel(category)) {
+ return null;
+ }
+
+ const modeResult = await clack.select({
+ message: 'Generation mode',
+ options: [
+ {
+ value: 'simple',
+ label: 'Simple Mode - Basic Zod schemas (recommended)',
+ hint: 'Generates simple string/number parameters with defaults',
+ },
+ {
+ value: 'advanced',
+ label: 'Advanced Mode - Full control',
+ hint: 'Configure parameters, returns, env vars, and AI agent guidance',
+ },
+ ],
+ });
+
+ if (clack.isCancel(modeResult)) {
+ return null;
+ }
+
+ const mode = modeResult as 'simple' | 'advanced';
+
+ return {
+ category: category as string,
+ mode,
+ };
+}
+
+/**
+ * Prompts for output path
+ */
+export async function promptOutputPath(defaultPath: string): Promise {
+ const outputPath = await clack.text({
+ message: 'Where should we create the package?',
+ placeholder: defaultPath,
+ initialValue: defaultPath,
+ validate: (value) => {
+ if (!value) return 'Output path is required';
+ },
+ });
+
+ if (clack.isCancel(outputPath)) {
+ return null;
+ }
+
+ return outputPath as string;
+}
+
+/**
+ * Prompts for final confirmation
+ */
+export async function promptConfirmation(
+ packageName: string,
+ toolCount: number,
+ outputPath: string
+): Promise {
+ const confirmed = await clack.confirm({
+ message: `Ready to generate ${packageName} with ${toolCount} tools at ${outputPath}?`,
+ initialValue: true,
+ });
+
+ if (clack.isCancel(confirmed)) {
+ return false;
+ }
+
+ return confirmed;
+}
diff --git a/packages/tools/create-basic-tools/src/prompts/basic.ts b/packages/tools/create-basic-tools/src/prompts/basic.ts
new file mode 100644
index 0000000..0e00b5b
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/prompts/basic.ts
@@ -0,0 +1,70 @@
+import * as clack from '@clack/prompts';
+import type { PackageInfo } from '../types.js';
+import { validateNpmPackageName } from '../validation/package-name.js';
+
+/**
+ * Prompts for basic package information
+ */
+export async function promptBasicInfo(): Promise {
+ const name = await clack.text({
+ message: 'Package name',
+ placeholder: '@myorg/content-tools',
+ validate: (value) => {
+ if (!value) return 'Package name is required';
+ const validation = validateNpmPackageName(value);
+ if (!validation.valid) {
+ return validation.errors?.[0] || 'Invalid package name';
+ }
+ },
+ });
+
+ if (clack.isCancel(name)) {
+ return null;
+ }
+
+ const description = await clack.text({
+ message: 'Package description',
+ placeholder: 'AI SDK tools for content processing',
+ validate: (value) => {
+ if (!value) return 'Description is required';
+ if (value.length < 10) return 'Description must be at least 10 characters';
+ },
+ });
+
+ if (clack.isCancel(description)) {
+ return null;
+ }
+
+ const author = await clack.text({
+ message: 'Author name',
+ placeholder: 'Your Name',
+ initialValue: '',
+ });
+
+ if (clack.isCancel(author)) {
+ return null;
+ }
+
+ const license = await clack.select({
+ message: 'License',
+ options: [
+ { value: 'MIT', label: 'MIT' },
+ { value: 'Apache-2.0', label: 'Apache-2.0' },
+ { value: 'ISC', label: 'ISC' },
+ { value: 'BSD-3-Clause', label: 'BSD-3-Clause' },
+ ],
+ initialValue: 'MIT',
+ });
+
+ if (clack.isCancel(license)) {
+ return null;
+ }
+
+ return {
+ name: name as string,
+ description: description as string,
+ author: author as string,
+ license: license as string,
+ category: '', // Will be set later
+ };
+}
diff --git a/packages/tools/create-basic-tools/src/prompts/tools.ts b/packages/tools/create-basic-tools/src/prompts/tools.ts
new file mode 100644
index 0000000..7e00da0
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/prompts/tools.ts
@@ -0,0 +1,99 @@
+import * as clack from '@clack/prompts';
+import type { ToolDefinition } from '../types.js';
+import { validateExportName } from '../validation/package-name.js';
+import { validateDescription } from '../validation/tool-metadata.js';
+
+/**
+ * Prompts for tool definitions (minimum 2 tools required)
+ */
+export async function promptTools(): Promise {
+ const tools: ToolDefinition[] = [];
+
+ clack.note(
+ 'Define at least 2 tools for your package.\nExamples: summarizeText, extractKeywords, classifySentiment',
+ 'Tool Definitions'
+ );
+
+ // First tool (required)
+ const tool1 = await promptSingleTool(1);
+ if (!tool1) return null;
+ tools.push(tool1);
+
+ // Second tool (required)
+ const tool2 = await promptSingleTool(2);
+ if (!tool2) return null;
+ tools.push(tool2);
+
+ // Additional tools (optional)
+ let continueAdding = true;
+ let toolNumber = 3;
+
+ while (continueAdding) {
+ const addMore = await clack.confirm({
+ message: `Add tool #${toolNumber}? (already have ${tools.length})`,
+ initialValue: toolNumber === 3, // Default yes for the 3rd tool
+ });
+
+ if (clack.isCancel(addMore)) {
+ return null;
+ }
+
+ if (!addMore) {
+ continueAdding = false;
+ } else {
+ const tool = await promptSingleTool(toolNumber);
+ if (!tool) return null;
+ tools.push(tool);
+ toolNumber++;
+ }
+ }
+
+ return tools;
+}
+
+/**
+ * Prompts for a single tool definition
+ */
+async function promptSingleTool(number: number): Promise {
+ const exportName = await clack.text({
+ message: `Tool #${number} export name`,
+ placeholder: number === 1 ? 'summarizeText' : number === 2 ? 'extractKeywords' : 'myTool',
+ validate: (value) => {
+ if (!value) return 'Export name is required';
+ const validation = validateExportName(value as string);
+ if (!validation.valid) {
+ return validation.error || 'Invalid export name';
+ }
+ },
+ });
+
+ if (clack.isCancel(exportName)) {
+ return null;
+ }
+
+ const description = await clack.text({
+ message: `Tool #${number} description`,
+ placeholder:
+ number === 1
+ ? 'Summarize a block of text into a concise overview.'
+ : number === 2
+ ? 'Extract important keywords from text.'
+ : 'Description of what this tool does.',
+ validate: (value) => {
+ if (!value) return 'Description is required';
+ const validation = validateDescription(value as string);
+ if (!validation.valid) {
+ return validation.error || 'Invalid description';
+ }
+ },
+ });
+
+ if (clack.isCancel(description)) {
+ return null;
+ }
+
+ return {
+ exportName: exportName as string,
+ description: description as string,
+ };
+}
diff --git a/packages/tools/create-basic-tools/src/types.ts b/packages/tools/create-basic-tools/src/types.ts
new file mode 100644
index 0000000..c414762
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/types.ts
@@ -0,0 +1,60 @@
+/**
+ * Shared TypeScript types for the TPMJS tool generator
+ */
+
+export interface ToolDefinition {
+ exportName: string;
+ description: string;
+ parameters?: ParameterDefinition[];
+ returns?: ReturnDefinition;
+ env?: string[];
+ frameworks?: string[];
+ aiAgent?: {
+ systemPrompt?: string;
+ model?: string;
+ };
+}
+
+export interface ParameterDefinition {
+ name: string;
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
+ description: string;
+ required: boolean;
+ default?: unknown;
+}
+
+export interface ReturnDefinition {
+ type: string;
+ description: string;
+}
+
+export interface PackageInfo {
+ name: string;
+ description: string;
+ author: string;
+ license: string;
+ category: string;
+}
+
+export interface GeneratorConfig {
+ packageInfo: PackageInfo;
+ tools: ToolDefinition[];
+ outputPath: string;
+ mode: 'simple' | 'advanced';
+}
+
+export interface CLIOptions {
+ name?: string;
+ description?: string;
+ category?: string;
+ tool?: string[];
+ output?: string;
+ yes?: boolean;
+}
+
+export interface GenerationResult {
+ success: boolean;
+ outputPath: string;
+ filesCreated: string[];
+ error?: string;
+}
diff --git a/packages/tools/create-basic-tools/src/utils/file-writer.ts b/packages/tools/create-basic-tools/src/utils/file-writer.ts
new file mode 100644
index 0000000..f85a8da
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/utils/file-writer.ts
@@ -0,0 +1,60 @@
+import * as fs from 'node:fs/promises';
+import * as path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+/**
+ * Ensures a directory exists, creating it if necessary
+ */
+export async function ensureDir(dirPath: string): Promise {
+ await fs.mkdir(dirPath, { recursive: true });
+}
+
+/**
+ * Writes a file with the given content
+ */
+export async function writeFile(filePath: string, content: string): Promise {
+ await fs.writeFile(filePath, content, 'utf-8');
+}
+
+/**
+ * Copies a template file to the destination
+ */
+export async function copyTemplate(
+ templateName: string,
+ destPath: string,
+ replacements?: Record
+): Promise {
+ const templatePath = path.join(__dirname, '../../templates', templateName);
+ let content = await fs.readFile(templatePath, 'utf-8');
+
+ // Apply replacements if provided
+ if (replacements) {
+ for (const [key, value] of Object.entries(replacements)) {
+ content = content.replaceAll(`{{${key}}}`, value);
+ }
+ }
+
+ await writeFile(destPath, content);
+}
+
+/**
+ * Checks if a path exists
+ */
+export async function pathExists(filePath: string): Promise {
+ try {
+ await fs.access(filePath);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+/**
+ * Gets the absolute path, resolving relative paths
+ */
+export function getAbsolutePath(inputPath: string): string {
+ return path.resolve(process.cwd(), inputPath);
+}
diff --git a/packages/tools/create-basic-tools/src/utils/logger.ts b/packages/tools/create-basic-tools/src/utils/logger.ts
new file mode 100644
index 0000000..388a228
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/utils/logger.ts
@@ -0,0 +1,41 @@
+import pc from 'picocolors';
+
+/**
+ * Logger utilities with colored output
+ */
+
+export function success(message: string): void {
+ console.log(pc.green(`✓ ${message}`));
+}
+
+export function error(message: string): void {
+ console.error(pc.red(`✗ ${message}`));
+}
+
+export function warn(message: string): void {
+ console.warn(pc.yellow(`⚠ ${message}`));
+}
+
+export function info(message: string): void {
+ console.log(pc.blue(`ℹ ${message}`));
+}
+
+export function dim(message: string): void {
+ console.log(pc.dim(message));
+}
+
+export function bold(message: string): string {
+ return pc.bold(message);
+}
+
+export function cyan(message: string): string {
+ return pc.cyan(message);
+}
+
+export function yellow(message: string): string {
+ return pc.yellow(message);
+}
+
+export function green(message: string): string {
+ return pc.green(message);
+}
diff --git a/packages/tools/create-basic-tools/src/validation/package-name.ts b/packages/tools/create-basic-tools/src/validation/package-name.ts
new file mode 100644
index 0000000..b73fb45
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/validation/package-name.ts
@@ -0,0 +1,89 @@
+import validatePackageName from 'validate-npm-package-name';
+
+export interface PackageNameValidation {
+ valid: boolean;
+ errors?: string[];
+ warnings?: string[];
+}
+
+/**
+ * Validates an npm package name
+ */
+export function validateNpmPackageName(name: string): PackageNameValidation {
+ const result = validatePackageName(name);
+
+ if (result.validForNewPackages) {
+ return {
+ valid: true,
+ warnings: result.warnings,
+ };
+ }
+
+ return {
+ valid: false,
+ errors: result.errors,
+ warnings: result.warnings,
+ };
+}
+
+/**
+ * Validates that export name is a valid JavaScript identifier
+ */
+export function validateExportName(name: string): { valid: boolean; error?: string } {
+ if (!name || name.length === 0) {
+ return { valid: false, error: 'Export name cannot be empty' };
+ }
+
+ // JavaScript identifier regex: must start with letter, $, or _, followed by letters, digits, $, or _
+ const identifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
+
+ if (!identifierRegex.test(name)) {
+ return {
+ valid: false,
+ error: 'Export name must be a valid JavaScript identifier (e.g., myTool, summarizeText)',
+ };
+ }
+
+ // Check for reserved words
+ const reservedWords = [
+ 'break',
+ 'case',
+ 'catch',
+ 'class',
+ 'const',
+ 'continue',
+ 'debugger',
+ 'default',
+ 'delete',
+ 'do',
+ 'else',
+ 'export',
+ 'extends',
+ 'finally',
+ 'for',
+ 'function',
+ 'if',
+ 'import',
+ 'in',
+ 'instanceof',
+ 'new',
+ 'return',
+ 'super',
+ 'switch',
+ 'this',
+ 'throw',
+ 'try',
+ 'typeof',
+ 'var',
+ 'void',
+ 'while',
+ 'with',
+ 'yield',
+ ];
+
+ if (reservedWords.includes(name)) {
+ return { valid: false, error: `"${name}" is a reserved JavaScript keyword` };
+ }
+
+ return { valid: true };
+}
diff --git a/packages/tools/create-basic-tools/src/validation/tool-metadata.ts b/packages/tools/create-basic-tools/src/validation/tool-metadata.ts
new file mode 100644
index 0000000..098569d
--- /dev/null
+++ b/packages/tools/create-basic-tools/src/validation/tool-metadata.ts
@@ -0,0 +1,72 @@
+import { TPMJS_CATEGORIES, TpmjsToolDefinitionSchema } from '@tpmjs/types/tpmjs';
+import type { TpmjsCategory } from '@tpmjs/types/tpmjs';
+import type { ToolDefinition } from '../types.js';
+
+/**
+ * Validates a tool definition against TPMJS schema
+ */
+export function validateToolDefinition(tool: ToolDefinition): {
+ valid: boolean;
+ errors?: string[];
+} {
+ const result = TpmjsToolDefinitionSchema.safeParse(tool);
+
+ if (result.success) {
+ return { valid: true };
+ }
+
+ const errors = result.error.issues.map((issue) => {
+ const path = issue.path.join('.');
+ return `${path}: ${issue.message}`;
+ });
+
+ return { valid: false, errors };
+}
+
+/**
+ * Validates that category is one of the allowed TPMJS categories
+ */
+export function validateCategory(category: string): {
+ valid: boolean;
+ error?: string;
+} {
+ if (!TPMJS_CATEGORIES.includes(category as TpmjsCategory)) {
+ return {
+ valid: false,
+ error: `Category must be one of: ${TPMJS_CATEGORIES.join(', ')}`,
+ };
+ }
+
+ return { valid: true };
+}
+
+/**
+ * Validates tool description length
+ */
+export function validateDescription(description: string): {
+ valid: boolean;
+ error?: string;
+} {
+ if (description.length < 20) {
+ return {
+ valid: false,
+ error: 'Description must be at least 20 characters',
+ };
+ }
+
+ if (description.length > 500) {
+ return {
+ valid: false,
+ error: 'Description must be at most 500 characters',
+ };
+ }
+
+ return { valid: true };
+}
+
+/**
+ * Get all available TPMJS categories
+ */
+export function getAvailableCategories(): readonly TpmjsCategory[] {
+ return TPMJS_CATEGORIES;
+}
diff --git a/packages/tools/create-basic-tools/templates/gitignore.txt b/packages/tools/create-basic-tools/templates/gitignore.txt
new file mode 100644
index 0000000..3a5c1d0
--- /dev/null
+++ b/packages/tools/create-basic-tools/templates/gitignore.txt
@@ -0,0 +1,6 @@
+node_modules
+dist
+.env
+.env.local
+*.log
+.DS_Store
diff --git a/packages/tools/create-basic-tools/templates/license-mit.txt b/packages/tools/create-basic-tools/templates/license-mit.txt
new file mode 100644
index 0000000..7e7f03f
--- /dev/null
+++ b/packages/tools/create-basic-tools/templates/license-mit.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) {{YEAR}} {{AUTHOR}}
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/tools/create-basic-tools/templates/npmignore.txt b/packages/tools/create-basic-tools/templates/npmignore.txt
new file mode 100644
index 0000000..bd6dabf
--- /dev/null
+++ b/packages/tools/create-basic-tools/templates/npmignore.txt
@@ -0,0 +1,7 @@
+src
+tsconfig.json
+tsup.config.ts
+.env
+.env.local
+*.log
+.DS_Store
diff --git a/packages/tools/create-basic-tools/tsconfig.json b/packages/tools/create-basic-tools/tsconfig.json
new file mode 100644
index 0000000..8934438
--- /dev/null
+++ b/packages/tools/create-basic-tools/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "@tpmjs/tsconfig/base.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "src",
+ "composite": false,
+ "incremental": false
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/packages/tools/create-basic-tools/tsup.config.ts b/packages/tools/create-basic-tools/tsup.config.ts
new file mode 100644
index 0000000..0015f1e
--- /dev/null
+++ b/packages/tools/create-basic-tools/tsup.config.ts
@@ -0,0 +1,12 @@
+import { defineConfig } from 'tsup';
+
+export default defineConfig({
+ entry: ['src/index.ts'],
+ format: ['esm'],
+ dts: true,
+ clean: true,
+ shims: true,
+ banner: {
+ js: '#!/usr/bin/env node',
+ },
+});
diff --git a/packages/ui/src/ToolHealthBadge/ToolHealthBadge.tsx b/packages/ui/src/ToolHealthBadge/ToolHealthBadge.tsx
index d9e3927..9e00517 100644
--- a/packages/ui/src/ToolHealthBadge/ToolHealthBadge.tsx
+++ b/packages/ui/src/ToolHealthBadge/ToolHealthBadge.tsx
@@ -22,10 +22,14 @@ export function ToolHealthBadge({
}: ToolHealthBadgeProps): React.ReactElement | null {
const isBroken = importHealth === 'BROKEN' || executionHealth === 'BROKEN';
+ console.log('🏥 [ToolHealthBadge] Render:', { importHealth, executionHealth, isBroken });
+
if (!isBroken) {
return null;
}
+ console.log('🚨 [ToolHealthBadge] Showing BROKEN badge!');
+
return (
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 62b6a34..fe8c06e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -502,6 +502,40 @@ importers:
specifier: ^5.9.3
version: 5.9.3
+ packages/tools/create-basic-tools:
+ dependencies:
+ '@clack/prompts':
+ specifier: ^0.7.0
+ version: 0.7.0
+ commander:
+ specifier: ^14.0.0
+ version: 14.0.2
+ picocolors:
+ specifier: ^1.0.0
+ version: 1.1.1
+ validate-npm-package-name:
+ specifier: ^5.0.0
+ version: 5.0.1
+ zod:
+ specifier: ^4.1.13
+ version: 4.1.13
+ devDependencies:
+ '@tpmjs/tsconfig':
+ specifier: workspace:*
+ version: link:../../config/tsconfig
+ '@tpmjs/types':
+ specifier: workspace:*
+ version: link:../../types
+ '@types/validate-npm-package-name':
+ specifier: ^4.0.2
+ version: 4.0.2
+ tsup:
+ specifier: ^8.3.5
+ version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)
+ typescript:
+ specifier: ^5.9.3
+ version: 5.9.3
+
packages/tools/createBlogPost:
dependencies:
zod:
@@ -947,6 +981,14 @@ packages:
'@chevrotain/utils@11.0.3':
resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==}
+ '@clack/core@0.3.5':
+ resolution: {integrity: sha512-5cfhQNH+1VQ2xLQlmzXMqUoiaH0lRBq9/CLW9lTyMbuKLC3+xEK01tHVvyut++mLOn5urSHmkm6I0Lg9MaJSTQ==}
+
+ '@clack/prompts@0.7.0':
+ resolution: {integrity: sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==}
+ bundledDependencies:
+ - is-unicode-supported
+
'@emnapi/core@1.7.1':
resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
@@ -2479,6 +2521,9 @@ packages:
'@types/uuid@9.0.8':
resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
+ '@types/validate-npm-package-name@4.0.2':
+ resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==}
+
'@typescript-eslint/eslint-plugin@8.48.0':
resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -5973,6 +6018,10 @@ packages:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
+ validate-npm-package-name@5.0.1:
+ resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
@@ -6647,6 +6696,17 @@ snapshots:
'@chevrotain/utils@11.0.3': {}
+ '@clack/core@0.3.5':
+ dependencies:
+ picocolors: 1.1.1
+ sisteransi: 1.0.5
+
+ '@clack/prompts@0.7.0':
+ dependencies:
+ '@clack/core': 0.3.5
+ picocolors: 1.1.1
+ sisteransi: 1.0.5
+
'@emnapi/core@1.7.1':
dependencies:
'@emnapi/wasi-threads': 1.1.0
@@ -7941,6 +8001,8 @@ snapshots:
'@types/uuid@9.0.8': {}
+ '@types/validate-npm-package-name@4.0.2': {}
+
'@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
@@ -12366,6 +12428,8 @@ snapshots:
uuid@9.0.1: {}
+ validate-npm-package-name@5.0.1: {}
+
vary@1.1.2: {}
vfile-location@5.0.3: