feat: simplify interactive CLI to only ask for package name

- Removed all prompts except package name
- Auto-generate description from package name
- Use sensible defaults: 2 example tools, ai-ml category, MIT license
- Generate exampleTool and anotherTool that users can customize
- Much faster UX - no more 10+ prompts for basic usage
- Updated README with simplified flow example
- Bumped version to 1.0.3

🤖 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-04 23:55:54 +10:00
parent 83afeef2dc
commit 3219da5a03
3 changed files with 74 additions and 100 deletions

View file

@ -1,15 +1,15 @@
# @tpmjs/create-basic-tools
CLI generator for scaffolding production-ready TPMJS tool packages with 2-3 tools by default.
CLI generator for scaffolding production-ready TPMJS tool packages. Just enter your package name and you're done!
## Features
- 🎯 **Multi-tool packages**: Generates packages with minimum 2 tools (ideally 2-3)
- ⚡ **Super fast**: Just asks for your package name, generates everything else
- 🎯 **2 example tools**: Start with working examples you can customize
- 🔧 **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/<toolName>.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
@ -21,14 +21,13 @@ CLI generator for scaffolding production-ready TPMJS tool packages with 2-3 tool
pnpmx @tpmjs/create-basic-tools
```
This will guide you through an interactive wizard that asks:
The CLI asks for just your package name and uses sensible defaults for everything else:
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
- **Description**: Auto-generated from package name
- **Tools**: 2 example tools you can customize
- **Category**: `ai-ml` (generic)
- **License**: MIT
- **Output**: Derived from package name
### Example Session
@ -40,54 +39,34 @@ $ pnpmx @tpmjs/create-basic-tools
◇ Package name
@myorg/content-tools
◇ Package description
│ AI SDK tools for content processing
◆ Generating package...
◇ 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
└ ✓ Success! Created @myorg/content-tools at ./content-tools
Files created:
src/tools/exampleTool.ts
src/tools/anotherTool.ts
src/index.ts
package.json
Next steps:
cd ./content-tools
pnpm install
pnpm build
pnpm type-check
pnpm publish
```
That's it! The generator creates 2 example tools you can rename and customize for your use case.
## Generated Package Structure
```
content-tools/
├── src/
│ ├── tools/ # One file per tool
│ │ ├── summarizeText.ts
│ │ ├── extractKeywords.ts
│ │ └── classifySentiment.ts
│ │ ├── exampleTool.ts
│ │ └── anotherTool.ts
│ └── index.ts # Re-exports all tools
├── dist/ # Build output (after pnpm build)
│ ├── index.js
@ -101,6 +80,8 @@ content-tools/
└── LICENSE
```
Simply rename `exampleTool.ts` and `anotherTool.ts` to match your use case, then customize the implementation.
## Generated Tool File Example
Each tool file follows this Zod-first pattern:
@ -109,7 +90,7 @@ Each tool file follows this Zod-first pattern:
import { tool } from 'ai';
import { z } from 'zod';
const SummarizeTextSchema = z.object({
const ExampleToolSchema = 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).'),
@ -117,12 +98,12 @@ const SummarizeTextSchema = z.object({
}).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<typeof SummarizeTextSchema>) {
export const exampleTool = tool({
description: 'An example tool - customize this for your use case',
inputSchema: ExampleToolSchema,
async execute(input: z.infer<typeof ExampleToolSchema>) {
// TODO: Implement the tool logic here
console.log('summarizeText called with:', input);
console.log('exampleTool called with:', input);
return {
success: true,

View file

@ -1,6 +1,6 @@
{
"name": "@tpmjs/create-basic-tools",
"version": "1.0.2",
"version": "1.0.3",
"description": "CLI generator for scaffolding production-ready TPMJS tool packages",
"type": "module",
"bin": {

View file

@ -4,9 +4,6 @@ import { generateTsConfig, generateTsupConfig } from './generators/config-files.
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,
@ -23,41 +20,25 @@ import * as logger from './utils/logger.js';
export async function runInteractiveCLI(): Promise<GenerationResult> {
clack.intro(logger.bold('create-tpmjs-tool'));
// Step 1: Get basic package info
const packageInfo = await promptBasicInfo();
if (!packageInfo) {
// Only ask for package name
const name = await clack.text({
message: 'Package name',
placeholder: '@yourname/my-tools',
validate: (value) => {
if (!value) return 'Package name is required';
if (!value.includes('/')) return 'Package name should be scoped (e.g., @yourname/my-tools)';
},
});
if (clack.isCancel(name)) {
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;
// Use defaults for everything else
const packageNameWithoutScope = (name as string).split('/').pop() || (name as string);
const defaultPath = `./${packageNameWithoutScope}`;
const outputPath = await promptOutputPath(defaultPath);
if (!outputPath) {
clack.cancel('Operation cancelled');
process.exit(0);
}
const absoluteOutputPath = getAbsolutePath(outputPath);
const absoluteOutputPath = getAbsolutePath(defaultPath);
// Check if directory exists
if (await pathExists(absoluteOutputPath)) {
@ -66,22 +47,34 @@ export async function runInteractiveCLI(): Promise<GenerationResult> {
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
// Generate with sensible defaults
const spinner = clack.spinner();
spinner.start('Generating package...');
const packageInfo = {
name: name as string,
description: `AI SDK tools for ${packageNameWithoutScope}`,
author: '',
license: 'MIT',
category: 'ai-ml',
};
const tools = [
{
exportName: 'exampleTool',
description: 'An example tool - customize this for your use case',
},
{
exportName: 'anotherTool',
description: 'Another example tool - add your implementation here',
},
];
const config: GeneratorConfig = {
packageInfo,
tools,
outputPath: absoluteOutputPath,
mode: categoryAndMode.mode,
mode: 'simple',
};
try {
@ -90,13 +83,13 @@ export async function runInteractiveCLI(): Promise<GenerationResult> {
spinner.stop('Package generated successfully!');
clack.outro(`
${logger.green('✓')} Success! Created ${logger.bold(packageInfo.name)} at ${logger.cyan(outputPath)}
${logger.green('✓')} Success! Created ${logger.bold(packageInfo.name)} at ${logger.cyan(defaultPath)}
Files created:
${result.filesCreated.map((f) => ` ${f}`).join('\n')}
Next steps:
${logger.cyan(`cd ${outputPath}`)}
${logger.cyan(`cd ${defaultPath}`)}
${logger.cyan('pnpm install')}
${logger.cyan('pnpm build')}
${logger.cyan('pnpm type-check')}