@neural-tools/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +80 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +84 -0
- package/dist/commands/deploy.d.ts +7 -0
- package/dist/commands/deploy.js +96 -0
- package/dist/commands/generate-agent.d.ts +10 -0
- package/dist/commands/generate-agent.js +126 -0
- package/dist/commands/generate-command.d.ts +10 -0
- package/dist/commands/generate-command.js +112 -0
- package/dist/commands/generate-mcp.d.ts +10 -0
- package/dist/commands/generate-mcp.js +429 -0
- package/dist/commands/login.d.ts +5 -0
- package/dist/commands/login.js +112 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +64 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +15 -0
- package/package.json +43 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Neural Tools License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Luke Amy. All rights reserved.
|
|
4
|
+
|
|
5
|
+
## License Agreement
|
|
6
|
+
|
|
7
|
+
This software is provided under a dual-license model:
|
|
8
|
+
|
|
9
|
+
### 1. Free Tier License (MIT)
|
|
10
|
+
|
|
11
|
+
The following components are licensed under the MIT License:
|
|
12
|
+
|
|
13
|
+
- Basic MCP generation functionality
|
|
14
|
+
- Claude command generation
|
|
15
|
+
- Core utilities and types
|
|
16
|
+
- Basic templates
|
|
17
|
+
- Documentation and examples
|
|
18
|
+
|
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of the free tier components to use, copy, modify, merge, publish, and distribute, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
### 2. Pro/Enterprise License (Proprietary)
|
|
24
|
+
|
|
25
|
+
The following features require a valid Pro or Enterprise license:
|
|
26
|
+
|
|
27
|
+
**Pro Features:**
|
|
28
|
+
- Vector database integration
|
|
29
|
+
- Semantic caching
|
|
30
|
+
- Fine-tuning workflows
|
|
31
|
+
- Cloud deployment templates (AWS/GCP)
|
|
32
|
+
- Premium templates and examples
|
|
33
|
+
- GitHub automation features
|
|
34
|
+
|
|
35
|
+
**Enterprise Features:**
|
|
36
|
+
- White-label support
|
|
37
|
+
- Custom integrations
|
|
38
|
+
- Priority support
|
|
39
|
+
- SLA guarantees
|
|
40
|
+
- Team collaboration features
|
|
41
|
+
|
|
42
|
+
These features are proprietary and may not be used without a valid license key purchased from neural-tools.dev.
|
|
43
|
+
|
|
44
|
+
### License Terms
|
|
45
|
+
|
|
46
|
+
1. **Free Tier**: You may use the free tier features for any purpose, including commercial use, under the MIT License terms.
|
|
47
|
+
|
|
48
|
+
2. **Pro/Enterprise**: You must purchase a license to access Pro or Enterprise features. Each license is:
|
|
49
|
+
- Per-user for individual licenses
|
|
50
|
+
- Per-organization for team/enterprise licenses
|
|
51
|
+
- Non-transferable without written consent
|
|
52
|
+
- Subject to the terms at neural-tools.dev/terms
|
|
53
|
+
|
|
54
|
+
3. **Source Code**: This repository is private. You may not:
|
|
55
|
+
- Redistribute the source code
|
|
56
|
+
- Create derivative works for redistribution
|
|
57
|
+
- Reverse engineer Pro/Enterprise features
|
|
58
|
+
- Remove or circumvent license checks
|
|
59
|
+
|
|
60
|
+
4. **Support**: Support is provided based on your license tier:
|
|
61
|
+
- Free: Community support only
|
|
62
|
+
- Pro: Email support (48-hour response)
|
|
63
|
+
- Enterprise: Priority support with SLA
|
|
64
|
+
|
|
65
|
+
### Warranty Disclaimer
|
|
66
|
+
|
|
67
|
+
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.
|
|
68
|
+
|
|
69
|
+
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.
|
|
70
|
+
|
|
71
|
+
### Contact
|
|
72
|
+
|
|
73
|
+
For licensing inquiries:
|
|
74
|
+
- Email: licensing@neural-tools.dev
|
|
75
|
+
- Website: https://neural-tools.dev/pricing
|
|
76
|
+
- Support: support@neural-tools.dev
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
**Last Updated:** January 2025
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const core_1 = require("@neural-tools/core");
|
|
6
|
+
const generate_mcp_1 = require("./commands/generate-mcp");
|
|
7
|
+
const generate_command_1 = require("./commands/generate-command");
|
|
8
|
+
const generate_agent_1 = require("./commands/generate-agent");
|
|
9
|
+
const deploy_1 = require("./commands/deploy");
|
|
10
|
+
const login_1 = require("./commands/login");
|
|
11
|
+
const status_1 = require("./commands/status");
|
|
12
|
+
const program = new commander_1.Command();
|
|
13
|
+
program
|
|
14
|
+
.name('neural-tools')
|
|
15
|
+
.description('Neural Tools - Build MCPs, Claude commands, and AI workflows')
|
|
16
|
+
.version('0.1.0');
|
|
17
|
+
// Generate commands
|
|
18
|
+
const generate = program
|
|
19
|
+
.command('generate')
|
|
20
|
+
.alias('g')
|
|
21
|
+
.description('Generate new components (MCP, command, agent, etc.)');
|
|
22
|
+
generate
|
|
23
|
+
.command('mcp')
|
|
24
|
+
.description('Generate a new MCP server')
|
|
25
|
+
.argument('<name>', 'Name of the MCP server')
|
|
26
|
+
.option('-d, --description <desc>', 'Description of the MCP')
|
|
27
|
+
.option('-o, --output <dir>', 'Output directory', './apps')
|
|
28
|
+
.option('--fastmcp', 'Use FastMCP template', true)
|
|
29
|
+
.option('--cicd <provider>', 'CI/CD provider (github, harness, none)', 'github')
|
|
30
|
+
.option('--deployment <platform>', 'Deployment platform (aws, gcp, none)', 'aws')
|
|
31
|
+
.option('--dry-run', 'Preview without creating files', false)
|
|
32
|
+
.action(generate_mcp_1.generateMCP);
|
|
33
|
+
generate
|
|
34
|
+
.command('command')
|
|
35
|
+
.description('Generate a new Claude command')
|
|
36
|
+
.argument('<name>', 'Name of the command (without /)')
|
|
37
|
+
.option('-d, --description <desc>', 'Description of the command')
|
|
38
|
+
.option('-o, --output <dir>', 'Output directory', './claude/commands')
|
|
39
|
+
.option('--args <arguments...>', 'Command arguments')
|
|
40
|
+
.option('--tools <tools...>', 'Allowed tools')
|
|
41
|
+
.option('--global', 'Install globally to ~/.claude/commands', false)
|
|
42
|
+
.option('--dry-run', 'Preview without creating files', false)
|
|
43
|
+
.action(generate_command_1.generateCommand);
|
|
44
|
+
generate
|
|
45
|
+
.command('agent')
|
|
46
|
+
.description('Generate a new Claude agent')
|
|
47
|
+
.argument('<name>', 'Name of the agent')
|
|
48
|
+
.option('-d, --description <desc>', 'Description of the agent')
|
|
49
|
+
.option('-o, --output <dir>', 'Output directory', './claude/agents')
|
|
50
|
+
.option('--model <model>', 'Model to use (sonnet, opus, haiku)', 'sonnet')
|
|
51
|
+
.option('--tools <tools...>', 'Available tools')
|
|
52
|
+
.option('--global', 'Install globally to ~/.claude/agents', false)
|
|
53
|
+
.option('--dry-run', 'Preview without creating files', false)
|
|
54
|
+
.action(generate_agent_1.generateAgent);
|
|
55
|
+
// Deploy command
|
|
56
|
+
program
|
|
57
|
+
.command('deploy')
|
|
58
|
+
.description('Deploy an MCP server')
|
|
59
|
+
.argument('<name>', 'Name of the MCP to deploy')
|
|
60
|
+
.option('-p, --platform <platform>', 'Deployment platform (aws, gcp)', 'aws')
|
|
61
|
+
.option('--region <region>', 'AWS/GCP region')
|
|
62
|
+
.option('--env <env>', 'Environment (dev, staging, prod)', 'dev')
|
|
63
|
+
.action(deploy_1.deployMCP);
|
|
64
|
+
// License management
|
|
65
|
+
program
|
|
66
|
+
.command('login')
|
|
67
|
+
.description('Authenticate and manage your license')
|
|
68
|
+
.option('--key <key>', 'License key')
|
|
69
|
+
.action(login_1.loginCommand);
|
|
70
|
+
program
|
|
71
|
+
.command('status')
|
|
72
|
+
.description('Show license status and available features')
|
|
73
|
+
.action(status_1.statusCommand);
|
|
74
|
+
// Error handling
|
|
75
|
+
program.exitOverride();
|
|
76
|
+
try {
|
|
77
|
+
program.parse(process.argv);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (error.code !== 'commander.help' && error.code !== 'commander.version') {
|
|
81
|
+
core_1.logger.error(error.message || 'An unexpected error occurred');
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.deployMCP = deployMCP;
|
|
7
|
+
const core_1 = require("@neural-tools/core");
|
|
8
|
+
const execa_1 = require("execa");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
|
+
async function deployMCP(name, options) {
|
|
12
|
+
core_1.logger.header(`Deploying MCP: ${name}`);
|
|
13
|
+
// Check license for cloud deployment
|
|
14
|
+
await (0, core_1.requireFeature)('cloud-deployment', 'Cloud Deployment');
|
|
15
|
+
const platform = options.platform || 'aws';
|
|
16
|
+
const env = options.env || 'dev';
|
|
17
|
+
core_1.logger.info(`Platform: ${platform}`);
|
|
18
|
+
core_1.logger.info(`Environment: ${env}`);
|
|
19
|
+
// Find MCP directory
|
|
20
|
+
const mcpDir = path_1.default.resolve('./apps', name);
|
|
21
|
+
if (!await fs_extra_1.default.pathExists(mcpDir)) {
|
|
22
|
+
throw new Error(`MCP "${name}" not found at ${mcpDir}`);
|
|
23
|
+
}
|
|
24
|
+
core_1.logger.startSpinner('Building MCP...');
|
|
25
|
+
try {
|
|
26
|
+
// Build the MCP
|
|
27
|
+
await (0, execa_1.execa)('npm', ['run', 'build'], { cwd: mcpDir, stdio: 'pipe' });
|
|
28
|
+
core_1.logger.succeedSpinner('MCP built successfully');
|
|
29
|
+
if (platform === 'aws') {
|
|
30
|
+
await deployToAWS(name, mcpDir, options);
|
|
31
|
+
}
|
|
32
|
+
else if (platform === 'gcp') {
|
|
33
|
+
await deployToGCP(name, mcpDir, options);
|
|
34
|
+
}
|
|
35
|
+
core_1.logger.success(`✨ MCP "${name}" deployed successfully!`);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
core_1.logger.failSpinner('Deployment failed');
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function deployToAWS(name, mcpDir, options) {
|
|
43
|
+
core_1.logger.startSpinner('Deploying to AWS Lambda...');
|
|
44
|
+
// TODO: Implement AWS Lambda deployment
|
|
45
|
+
// This would use AWS CDK or SAM to deploy
|
|
46
|
+
// For now, just a placeholder
|
|
47
|
+
core_1.logger.updateSpinner('Packaging Lambda function...');
|
|
48
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
49
|
+
core_1.logger.updateSpinner('Uploading to S3...');
|
|
50
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
51
|
+
core_1.logger.updateSpinner('Creating/updating Lambda function...');
|
|
52
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
53
|
+
core_1.logger.succeedSpinner('Deployed to AWS Lambda');
|
|
54
|
+
core_1.logger.section('Deployment Info', [
|
|
55
|
+
`Function: ${name}-${options.env}`,
|
|
56
|
+
`Region: ${options.region || 'us-east-1'}`,
|
|
57
|
+
`Environment: ${options.env}`,
|
|
58
|
+
'',
|
|
59
|
+
'Configure in Claude Code:',
|
|
60
|
+
JSON.stringify({
|
|
61
|
+
mcpServers: {
|
|
62
|
+
[name]: {
|
|
63
|
+
command: 'aws',
|
|
64
|
+
args: [
|
|
65
|
+
'lambda',
|
|
66
|
+
'invoke',
|
|
67
|
+
'--function-name',
|
|
68
|
+
`${name}-${options.env}`,
|
|
69
|
+
'--payload',
|
|
70
|
+
'stdin',
|
|
71
|
+
'--output',
|
|
72
|
+
'stdout'
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}, null, 2)
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
async function deployToGCP(name, mcpDir, options) {
|
|
80
|
+
core_1.logger.startSpinner('Deploying to Google Cloud Functions...');
|
|
81
|
+
// TODO: Implement GCP Cloud Functions deployment
|
|
82
|
+
// This would use gcloud CLI or Terraform
|
|
83
|
+
// For now, just a placeholder
|
|
84
|
+
core_1.logger.updateSpinner('Packaging function...');
|
|
85
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
86
|
+
core_1.logger.updateSpinner('Uploading to Cloud Storage...');
|
|
87
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
88
|
+
core_1.logger.updateSpinner('Deploying Cloud Function...');
|
|
89
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
90
|
+
core_1.logger.succeedSpinner('Deployed to Google Cloud Functions');
|
|
91
|
+
core_1.logger.section('Deployment Info', [
|
|
92
|
+
`Function: ${name}-${options.env}`,
|
|
93
|
+
`Region: ${options.region || 'us-central1'}`,
|
|
94
|
+
`Environment: ${options.env}`
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface GenerateAgentOptions {
|
|
2
|
+
description?: string;
|
|
3
|
+
output?: string;
|
|
4
|
+
model?: 'sonnet' | 'opus' | 'haiku';
|
|
5
|
+
tools?: string[];
|
|
6
|
+
global?: boolean;
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateAgent(name: string, options: GenerateAgentOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateAgent = generateAgent;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const core_1 = require("@neural-tools/core");
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
async function generateAgent(name, options) {
|
|
13
|
+
core_1.logger.header(`Generating Claude Agent: ${name}`);
|
|
14
|
+
// Prompt for missing information
|
|
15
|
+
let description = options.description;
|
|
16
|
+
if (!description) {
|
|
17
|
+
const answers = await inquirer_1.default.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'input',
|
|
20
|
+
name: 'description',
|
|
21
|
+
message: 'Description of your agent:',
|
|
22
|
+
default: `${name} specialized agent`
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
description = answers.description;
|
|
26
|
+
}
|
|
27
|
+
// Determine output directory
|
|
28
|
+
let outputDir;
|
|
29
|
+
if (options.global) {
|
|
30
|
+
outputDir = path_1.default.join(os_1.default.homedir(), '.claude', 'agents');
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
outputDir = path_1.default.resolve(options.output || './claude/agents');
|
|
34
|
+
}
|
|
35
|
+
const agentFile = path_1.default.join(outputDir, `${name}.md`);
|
|
36
|
+
const model = options.model || 'sonnet';
|
|
37
|
+
if (options.dryRun) {
|
|
38
|
+
core_1.logger.info('Dry run mode - no files will be created');
|
|
39
|
+
core_1.logger.section('Configuration', [
|
|
40
|
+
`Name: ${name}`,
|
|
41
|
+
`Description: ${description}`,
|
|
42
|
+
`Output: ${agentFile}`,
|
|
43
|
+
`Model: ${model}`,
|
|
44
|
+
`Tools: ${options.tools?.join(', ') || 'all'}`,
|
|
45
|
+
`Global: ${options.global ? 'Yes' : 'No'}`
|
|
46
|
+
]);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Check if file already exists
|
|
50
|
+
if (await fs_extra_1.default.pathExists(agentFile)) {
|
|
51
|
+
const { overwrite } = await inquirer_1.default.prompt([
|
|
52
|
+
{
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
name: 'overwrite',
|
|
55
|
+
message: `Agent ${name} already exists. Overwrite?`,
|
|
56
|
+
default: false
|
|
57
|
+
}
|
|
58
|
+
]);
|
|
59
|
+
if (!overwrite) {
|
|
60
|
+
core_1.logger.warn('Cancelled');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
core_1.logger.startSpinner('Creating Claude agent...');
|
|
65
|
+
try {
|
|
66
|
+
await fs_extra_1.default.ensureDir(outputDir);
|
|
67
|
+
// Build frontmatter
|
|
68
|
+
const frontmatter = ['---'];
|
|
69
|
+
frontmatter.push(`model: claude-${model}-4-5`);
|
|
70
|
+
if (options.tools && options.tools.length > 0) {
|
|
71
|
+
frontmatter.push(`tools:`);
|
|
72
|
+
options.tools.forEach(tool => {
|
|
73
|
+
frontmatter.push(` - ${tool}`);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
frontmatter.push('---');
|
|
77
|
+
frontmatter.push('');
|
|
78
|
+
// Build agent content
|
|
79
|
+
const agentContent = `${frontmatter.join('\n')}# ${name} Agent
|
|
80
|
+
|
|
81
|
+
${description}
|
|
82
|
+
|
|
83
|
+
## Role
|
|
84
|
+
|
|
85
|
+
You are a specialized agent for ${name} tasks. Your primary responsibilities include:
|
|
86
|
+
|
|
87
|
+
- [Responsibility 1]
|
|
88
|
+
- [Responsibility 2]
|
|
89
|
+
- [Responsibility 3]
|
|
90
|
+
|
|
91
|
+
## Guidelines
|
|
92
|
+
|
|
93
|
+
When performing ${name} tasks:
|
|
94
|
+
|
|
95
|
+
1. [Guideline 1]
|
|
96
|
+
2. [Guideline 2]
|
|
97
|
+
3. [Guideline 3]
|
|
98
|
+
|
|
99
|
+
## Output Format
|
|
100
|
+
|
|
101
|
+
Provide clear, structured responses that:
|
|
102
|
+
- [Output requirement 1]
|
|
103
|
+
- [Output requirement 2]
|
|
104
|
+
- [Output requirement 3]
|
|
105
|
+
|
|
106
|
+
Focus on ${name} and deliver actionable results.
|
|
107
|
+
`;
|
|
108
|
+
await fs_extra_1.default.writeFile(agentFile, agentContent, 'utf-8');
|
|
109
|
+
core_1.logger.succeedSpinner('Claude agent created successfully!');
|
|
110
|
+
core_1.logger.section('Next steps', [
|
|
111
|
+
options.global
|
|
112
|
+
? `Agent ${name} is now available globally in Claude Code`
|
|
113
|
+
: `Add the agent to your project by copying ${agentFile}`,
|
|
114
|
+
'',
|
|
115
|
+
'Customize the agent by editing:',
|
|
116
|
+
` ${agentFile}`,
|
|
117
|
+
'',
|
|
118
|
+
'Use the agent via the Task tool in Claude Code'
|
|
119
|
+
]);
|
|
120
|
+
core_1.logger.success(`✨ Agent "${name}" ready to use!`);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
core_1.logger.failSpinner('Failed to create agent');
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface GenerateCommandOptions {
|
|
2
|
+
description?: string;
|
|
3
|
+
output?: string;
|
|
4
|
+
args?: string[];
|
|
5
|
+
tools?: string[];
|
|
6
|
+
global?: boolean;
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateCommand(name: string, options: GenerateCommandOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateCommand = generateCommand;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const core_1 = require("@neural-tools/core");
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
async function generateCommand(name, options) {
|
|
13
|
+
core_1.logger.header(`Generating Claude Command: /${name}`);
|
|
14
|
+
// Prompt for missing information
|
|
15
|
+
let description = options.description;
|
|
16
|
+
if (!description) {
|
|
17
|
+
const answers = await inquirer_1.default.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'input',
|
|
20
|
+
name: 'description',
|
|
21
|
+
message: 'Description of your command:',
|
|
22
|
+
default: `Execute ${name}`
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
description = answers.description;
|
|
26
|
+
}
|
|
27
|
+
// Determine output directory
|
|
28
|
+
let outputDir;
|
|
29
|
+
if (options.global) {
|
|
30
|
+
outputDir = path_1.default.join(os_1.default.homedir(), '.claude', 'commands');
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
outputDir = path_1.default.resolve(options.output || './claude/commands');
|
|
34
|
+
}
|
|
35
|
+
const commandFile = path_1.default.join(outputDir, `${name}.md`);
|
|
36
|
+
if (options.dryRun) {
|
|
37
|
+
core_1.logger.info('Dry run mode - no files will be created');
|
|
38
|
+
core_1.logger.section('Configuration', [
|
|
39
|
+
`Name: /${name}`,
|
|
40
|
+
`Description: ${description}`,
|
|
41
|
+
`Output: ${commandFile}`,
|
|
42
|
+
`Arguments: ${options.args?.join(', ') || 'none'}`,
|
|
43
|
+
`Allowed Tools: ${options.tools?.join(', ') || 'all'}`,
|
|
44
|
+
`Global: ${options.global ? 'Yes' : 'No'}`
|
|
45
|
+
]);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Check if file already exists
|
|
49
|
+
if (await fs_extra_1.default.pathExists(commandFile)) {
|
|
50
|
+
const { overwrite } = await inquirer_1.default.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: 'confirm',
|
|
53
|
+
name: 'overwrite',
|
|
54
|
+
message: `Command /${name} already exists. Overwrite?`,
|
|
55
|
+
default: false
|
|
56
|
+
}
|
|
57
|
+
]);
|
|
58
|
+
if (!overwrite) {
|
|
59
|
+
core_1.logger.warn('Cancelled');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
core_1.logger.startSpinner('Creating Claude command...');
|
|
64
|
+
try {
|
|
65
|
+
await fs_extra_1.default.ensureDir(outputDir);
|
|
66
|
+
// Build frontmatter
|
|
67
|
+
const frontmatter = ['---'];
|
|
68
|
+
if (options.args && options.args.length > 0) {
|
|
69
|
+
frontmatter.push(`argument-hint: ${options.args.join(' ')}`);
|
|
70
|
+
}
|
|
71
|
+
frontmatter.push(`description: ${description}`);
|
|
72
|
+
if (options.tools && options.tools.length > 0) {
|
|
73
|
+
frontmatter.push(`allowed-tools:`);
|
|
74
|
+
options.tools.forEach(tool => {
|
|
75
|
+
frontmatter.push(` - ${tool}`);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
frontmatter.push('---');
|
|
79
|
+
frontmatter.push('');
|
|
80
|
+
// Build command content
|
|
81
|
+
const argsList = options.args || [];
|
|
82
|
+
const argPlaceholders = argsList.map((arg, i) => `$${i + 1}`).join(' ');
|
|
83
|
+
const argDescription = argsList.length > 0
|
|
84
|
+
? `\n\nArguments:\n${argsList.map((arg, i) => `- $${i + 1}: ${arg}`).join('\n')}`
|
|
85
|
+
: '';
|
|
86
|
+
const commandContent = `${frontmatter.join('\n')}# ${name} Command
|
|
87
|
+
|
|
88
|
+
Execute the ${name} operation${argDescription ? ':' + argDescription : '.'}
|
|
89
|
+
|
|
90
|
+
${argPlaceholders ? `Using arguments: ${argPlaceholders}` : ''}
|
|
91
|
+
|
|
92
|
+
Please proceed with the ${name} operation.
|
|
93
|
+
`;
|
|
94
|
+
await fs_extra_1.default.writeFile(commandFile, commandContent, 'utf-8');
|
|
95
|
+
core_1.logger.succeedSpinner('Claude command created successfully!');
|
|
96
|
+
core_1.logger.section('Next steps', [
|
|
97
|
+
options.global
|
|
98
|
+
? `Command /${name} is now available globally in Claude Code`
|
|
99
|
+
: `Add the command to your project by copying ${commandFile}`,
|
|
100
|
+
'',
|
|
101
|
+
'Usage:',
|
|
102
|
+
argsList.length > 0
|
|
103
|
+
? ` /${name} ${argsList.join(' ')}`
|
|
104
|
+
: ` /${name}`
|
|
105
|
+
]);
|
|
106
|
+
core_1.logger.success(`✨ Command "/${name}" ready to use!`);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
core_1.logger.failSpinner('Failed to create command');
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface GenerateMCPOptions {
|
|
2
|
+
description?: string;
|
|
3
|
+
output?: string;
|
|
4
|
+
fastmcp?: boolean;
|
|
5
|
+
cicd?: 'github' | 'harness' | 'none';
|
|
6
|
+
deployment?: 'aws' | 'gcp' | 'none';
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateMCP(name: string, options: GenerateMCPOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateMCP = generateMCP;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const core_1 = require("@neural-tools/core");
|
|
10
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
|
+
async function generateMCP(name, options) {
|
|
12
|
+
core_1.logger.header(`Generating MCP: ${name}`);
|
|
13
|
+
// Check license for cloud deployment
|
|
14
|
+
if (options.deployment !== 'none') {
|
|
15
|
+
await (0, core_1.requireFeature)('cloud-deployment', 'Cloud Deployment');
|
|
16
|
+
}
|
|
17
|
+
// Prompt for missing information
|
|
18
|
+
let description = options.description;
|
|
19
|
+
if (!description) {
|
|
20
|
+
const answers = await inquirer_1.default.prompt([
|
|
21
|
+
{
|
|
22
|
+
type: 'input',
|
|
23
|
+
name: 'description',
|
|
24
|
+
message: 'Description of your MCP:',
|
|
25
|
+
default: `${name} MCP server`
|
|
26
|
+
}
|
|
27
|
+
]);
|
|
28
|
+
description = answers.description;
|
|
29
|
+
}
|
|
30
|
+
const outputDir = path_1.default.resolve(options.output || './apps', name);
|
|
31
|
+
if (options.dryRun) {
|
|
32
|
+
core_1.logger.info('Dry run mode - no files will be created');
|
|
33
|
+
core_1.logger.section('Configuration', [
|
|
34
|
+
`Name: ${name}`,
|
|
35
|
+
`Description: ${description}`,
|
|
36
|
+
`Output: ${outputDir}`,
|
|
37
|
+
`Template: ${options.fastmcp ? 'FastMCP' : 'Standard'}`,
|
|
38
|
+
`CI/CD: ${options.cicd}`,
|
|
39
|
+
`Deployment: ${options.deployment}`
|
|
40
|
+
]);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Check if directory already exists
|
|
44
|
+
if (await fs_extra_1.default.pathExists(outputDir)) {
|
|
45
|
+
const { overwrite } = await inquirer_1.default.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: 'confirm',
|
|
48
|
+
name: 'overwrite',
|
|
49
|
+
message: `Directory ${outputDir} already exists. Overwrite?`,
|
|
50
|
+
default: false
|
|
51
|
+
}
|
|
52
|
+
]);
|
|
53
|
+
if (!overwrite) {
|
|
54
|
+
core_1.logger.warn('Cancelled');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
await fs_extra_1.default.remove(outputDir);
|
|
58
|
+
}
|
|
59
|
+
core_1.logger.startSpinner('Creating MCP structure...');
|
|
60
|
+
try {
|
|
61
|
+
// Create directory structure
|
|
62
|
+
await fs_extra_1.default.ensureDir(outputDir);
|
|
63
|
+
// Create pyproject.toml
|
|
64
|
+
const pyprojectContent = `[project]
|
|
65
|
+
name = "mcp-${name}"
|
|
66
|
+
version = "0.1.0"
|
|
67
|
+
description = "${description}"
|
|
68
|
+
requires-python = ">=3.10"
|
|
69
|
+
dependencies = [
|
|
70
|
+
"fastmcp>=2.2.0",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[project.optional-dependencies]
|
|
74
|
+
dev = [
|
|
75
|
+
"pytest>=7.0.0",
|
|
76
|
+
"black>=23.0.0",
|
|
77
|
+
"ruff>=0.1.0",
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
[build-system]
|
|
81
|
+
requires = ["hatchling"]
|
|
82
|
+
build-backend = "hatchling.build"
|
|
83
|
+
|
|
84
|
+
[tool.black]
|
|
85
|
+
line-length = 100
|
|
86
|
+
|
|
87
|
+
[tool.ruff]
|
|
88
|
+
line-length = 100
|
|
89
|
+
`;
|
|
90
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputDir, 'pyproject.toml'), pyprojectContent, 'utf-8');
|
|
91
|
+
// Create main server.py with FastMCP
|
|
92
|
+
const serverContent = `"""
|
|
93
|
+
${name} MCP Server
|
|
94
|
+
|
|
95
|
+
${description}
|
|
96
|
+
"""
|
|
97
|
+
from fastmcp import FastMCP
|
|
98
|
+
|
|
99
|
+
mcp = FastMCP("${name}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@mcp.tool()
|
|
103
|
+
def add_numbers(a: int, b: int) -> int:
|
|
104
|
+
"""Add two numbers together"""
|
|
105
|
+
return a + b
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@mcp.tool()
|
|
109
|
+
async def process_message(message: str) -> str:
|
|
110
|
+
"""Process a message and return the result"""
|
|
111
|
+
return f"Processed: {message}"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@mcp.resource("config://version")
|
|
115
|
+
def get_version() -> str:
|
|
116
|
+
"""Get the current version of the MCP server"""
|
|
117
|
+
return "0.1.0"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@mcp.resource("example://data/{item_id}")
|
|
121
|
+
async def get_item(item_id: str) -> str:
|
|
122
|
+
"""Get an item by ID"""
|
|
123
|
+
return f"Item data for: {item_id}"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@mcp.prompt()
|
|
127
|
+
def review_code(code: str) -> str:
|
|
128
|
+
"""Generate a code review prompt"""
|
|
129
|
+
return f"""Please review this code:
|
|
130
|
+
|
|
131
|
+
\`\`\`python
|
|
132
|
+
{code}
|
|
133
|
+
\`\`\`
|
|
134
|
+
|
|
135
|
+
Provide feedback on:
|
|
136
|
+
1. Code quality
|
|
137
|
+
2. Potential bugs
|
|
138
|
+
3. Performance improvements
|
|
139
|
+
4. Best practices
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@mcp.prompt()
|
|
144
|
+
def brainstorm_topic(topic: str) -> str:
|
|
145
|
+
"""Generate a brainstorming prompt"""
|
|
146
|
+
return f"Let's brainstorm ideas about: {topic}"
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
mcp.run()
|
|
151
|
+
`;
|
|
152
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputDir, 'server.py'), serverContent, 'utf-8');
|
|
153
|
+
// Create README
|
|
154
|
+
const readmeContent = `# ${name} MCP Server
|
|
155
|
+
|
|
156
|
+
${description}
|
|
157
|
+
|
|
158
|
+
## Quick Start with Docker
|
|
159
|
+
|
|
160
|
+
\`\`\`bash
|
|
161
|
+
# Start the MCP server
|
|
162
|
+
docker-compose up
|
|
163
|
+
|
|
164
|
+
# In another terminal, test it
|
|
165
|
+
docker-compose exec mcp python server.py
|
|
166
|
+
\`\`\`
|
|
167
|
+
|
|
168
|
+
## Local Development
|
|
169
|
+
|
|
170
|
+
### Prerequisites
|
|
171
|
+
|
|
172
|
+
- Python 3.10+
|
|
173
|
+
- uv (recommended) or pip
|
|
174
|
+
|
|
175
|
+
### Installation
|
|
176
|
+
|
|
177
|
+
\`\`\`bash
|
|
178
|
+
# Using uv (recommended)
|
|
179
|
+
uv pip install -e .
|
|
180
|
+
|
|
181
|
+
# Or using pip
|
|
182
|
+
pip install -e .
|
|
183
|
+
\`\`\`
|
|
184
|
+
|
|
185
|
+
### Running the Server
|
|
186
|
+
|
|
187
|
+
\`\`\`bash
|
|
188
|
+
# Development mode with MCP Inspector
|
|
189
|
+
fastmcp dev server.py
|
|
190
|
+
|
|
191
|
+
# Direct execution
|
|
192
|
+
python server.py
|
|
193
|
+
|
|
194
|
+
# Install to Claude Desktop
|
|
195
|
+
fastmcp install server.py
|
|
196
|
+
\`\`\`
|
|
197
|
+
|
|
198
|
+
## Usage with Claude Code
|
|
199
|
+
|
|
200
|
+
Add to your Claude Code settings (\`~/.config/claude/config.json\`):
|
|
201
|
+
|
|
202
|
+
\`\`\`json
|
|
203
|
+
{
|
|
204
|
+
"mcpServers": {
|
|
205
|
+
"${name}": {
|
|
206
|
+
"command": "python",
|
|
207
|
+
"args": ["/path/to/server.py"]
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
\`\`\`
|
|
212
|
+
|
|
213
|
+
Or use the Docker container:
|
|
214
|
+
|
|
215
|
+
\`\`\`json
|
|
216
|
+
{
|
|
217
|
+
"mcpServers": {
|
|
218
|
+
"${name}": {
|
|
219
|
+
"command": "docker",
|
|
220
|
+
"args": ["run", "-i", "mcp-${name}"]
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
\`\`\`
|
|
225
|
+
|
|
226
|
+
## Features
|
|
227
|
+
|
|
228
|
+
- **Tools**: Add numbers, process messages
|
|
229
|
+
- **Resources**: Get version, retrieve items by ID
|
|
230
|
+
- **Prompts**: Code review, brainstorming
|
|
231
|
+
|
|
232
|
+
## Project Structure
|
|
233
|
+
|
|
234
|
+
\`\`\`
|
|
235
|
+
.
|
|
236
|
+
├── server.py # Main MCP server
|
|
237
|
+
├── pyproject.toml # Python project configuration
|
|
238
|
+
├── Dockerfile # Docker image definition
|
|
239
|
+
├── docker-compose.yml # Local development setup
|
|
240
|
+
└── README.md # This file
|
|
241
|
+
\`\`\`
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
### Running Tests
|
|
246
|
+
|
|
247
|
+
\`\`\`bash
|
|
248
|
+
pytest
|
|
249
|
+
\`\`\`
|
|
250
|
+
|
|
251
|
+
### Code Formatting
|
|
252
|
+
|
|
253
|
+
\`\`\`bash
|
|
254
|
+
black .
|
|
255
|
+
ruff check .
|
|
256
|
+
\`\`\`
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
MIT
|
|
261
|
+
`;
|
|
262
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputDir, 'README.md'), readmeContent, 'utf-8');
|
|
263
|
+
// Create Dockerfile
|
|
264
|
+
const dockerfileContent = `FROM python:3.11-slim
|
|
265
|
+
|
|
266
|
+
WORKDIR /app
|
|
267
|
+
|
|
268
|
+
# Install uv for faster dependency installation
|
|
269
|
+
RUN pip install --no-cache-dir uv
|
|
270
|
+
|
|
271
|
+
# Copy project files
|
|
272
|
+
COPY pyproject.toml .
|
|
273
|
+
COPY server.py .
|
|
274
|
+
|
|
275
|
+
# Install dependencies
|
|
276
|
+
RUN uv pip install --system --no-cache .
|
|
277
|
+
|
|
278
|
+
# Run the MCP server
|
|
279
|
+
CMD ["python", "server.py"]
|
|
280
|
+
`;
|
|
281
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputDir, 'Dockerfile'), dockerfileContent, 'utf-8');
|
|
282
|
+
// Create docker-compose.yml
|
|
283
|
+
const dockerComposeContent = `version: '3.8'
|
|
284
|
+
|
|
285
|
+
services:
|
|
286
|
+
mcp:
|
|
287
|
+
build: .
|
|
288
|
+
image: mcp-${name}
|
|
289
|
+
container_name: ${name}-mcp
|
|
290
|
+
stdin_open: true
|
|
291
|
+
tty: true
|
|
292
|
+
volumes:
|
|
293
|
+
- .:/app
|
|
294
|
+
environment:
|
|
295
|
+
- PYTHONUNBUFFERED=1
|
|
296
|
+
`;
|
|
297
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputDir, 'docker-compose.yml'), dockerComposeContent, 'utf-8');
|
|
298
|
+
// Create .dockerignore
|
|
299
|
+
const dockerignoreContent = `__pycache__
|
|
300
|
+
*.pyc
|
|
301
|
+
*.pyo
|
|
302
|
+
*.pyd
|
|
303
|
+
.Python
|
|
304
|
+
*.so
|
|
305
|
+
*.egg
|
|
306
|
+
*.egg-info
|
|
307
|
+
dist
|
|
308
|
+
build
|
|
309
|
+
.pytest_cache
|
|
310
|
+
.ruff_cache
|
|
311
|
+
.venv
|
|
312
|
+
venv
|
|
313
|
+
.git
|
|
314
|
+
.github
|
|
315
|
+
README.md
|
|
316
|
+
`;
|
|
317
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputDir, '.dockerignore'), dockerignoreContent, 'utf-8');
|
|
318
|
+
// Add CI/CD if requested
|
|
319
|
+
if (options.cicd === 'github') {
|
|
320
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(outputDir, '.github', 'workflows'));
|
|
321
|
+
const workflowContent = `name: Deploy MCP
|
|
322
|
+
|
|
323
|
+
on:
|
|
324
|
+
push:
|
|
325
|
+
branches: [main]
|
|
326
|
+
pull_request:
|
|
327
|
+
branches: [main]
|
|
328
|
+
|
|
329
|
+
jobs:
|
|
330
|
+
build:
|
|
331
|
+
runs-on: ubuntu-latest
|
|
332
|
+
steps:
|
|
333
|
+
- uses: actions/checkout@v4
|
|
334
|
+
- uses: actions/setup-python@v5
|
|
335
|
+
with:
|
|
336
|
+
python-version: '3.11'
|
|
337
|
+
|
|
338
|
+
- name: Install uv
|
|
339
|
+
run: pip install uv
|
|
340
|
+
|
|
341
|
+
- name: Install dependencies
|
|
342
|
+
run: uv pip install --system -e ".[dev]"
|
|
343
|
+
|
|
344
|
+
- name: Run tests
|
|
345
|
+
run: pytest
|
|
346
|
+
|
|
347
|
+
- name: Check code formatting
|
|
348
|
+
run: |
|
|
349
|
+
black --check .
|
|
350
|
+
ruff check .
|
|
351
|
+
|
|
352
|
+
docker:
|
|
353
|
+
runs-on: ubuntu-latest
|
|
354
|
+
needs: build
|
|
355
|
+
steps:
|
|
356
|
+
- uses: actions/checkout@v4
|
|
357
|
+
|
|
358
|
+
- name: Build Docker image
|
|
359
|
+
run: docker build -t mcp-${name}:latest .
|
|
360
|
+
|
|
361
|
+
- name: Test Docker image
|
|
362
|
+
run: docker run --rm mcp-${name}:latest python -c "import fastmcp; print('OK')"
|
|
363
|
+
|
|
364
|
+
deploy:
|
|
365
|
+
needs: [build, docker]
|
|
366
|
+
runs-on: ubuntu-latest
|
|
367
|
+
if: github.ref == 'refs/heads/main'
|
|
368
|
+
steps:
|
|
369
|
+
- uses: actions/checkout@v4
|
|
370
|
+
${options.deployment === 'aws' ? `
|
|
371
|
+
- name: Configure AWS credentials
|
|
372
|
+
uses: aws-actions/configure-aws-credentials@v4
|
|
373
|
+
with:
|
|
374
|
+
aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
375
|
+
aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
376
|
+
aws-region: us-east-1
|
|
377
|
+
|
|
378
|
+
- name: Login to Amazon ECR
|
|
379
|
+
id: login-ecr
|
|
380
|
+
uses: aws-actions/amazon-ecr-login@v2
|
|
381
|
+
|
|
382
|
+
- name: Build and push Docker image
|
|
383
|
+
env:
|
|
384
|
+
ECR_REGISTRY: \${{ steps.login-ecr.outputs.registry }}
|
|
385
|
+
ECR_REPOSITORY: mcp-${name}
|
|
386
|
+
IMAGE_TAG: \${{ github.sha }}
|
|
387
|
+
run: |
|
|
388
|
+
docker build -t \$ECR_REGISTRY/\$ECR_REPOSITORY:\$IMAGE_TAG .
|
|
389
|
+
docker push \$ECR_REGISTRY/\$ECR_REPOSITORY:\$IMAGE_TAG
|
|
390
|
+
docker tag \$ECR_REGISTRY/\$ECR_REPOSITORY:\$IMAGE_TAG \$ECR_REGISTRY/\$ECR_REPOSITORY:latest
|
|
391
|
+
docker push \$ECR_REGISTRY/\$ECR_REPOSITORY:latest
|
|
392
|
+
` : ''}${options.deployment === 'gcp' ? `
|
|
393
|
+
- name: Authenticate to Google Cloud
|
|
394
|
+
uses: google-github-actions/auth@v2
|
|
395
|
+
with:
|
|
396
|
+
credentials_json: \${{ secrets.GCP_CREDENTIALS }}
|
|
397
|
+
|
|
398
|
+
- name: Set up Cloud SDK
|
|
399
|
+
uses: google-github-actions/setup-gcloud@v2
|
|
400
|
+
|
|
401
|
+
- name: Build and push Docker image
|
|
402
|
+
run: |
|
|
403
|
+
gcloud builds submit --tag gcr.io/\${{ secrets.GCP_PROJECT_ID }}/mcp-${name}:latest
|
|
404
|
+
` : ''}
|
|
405
|
+
`;
|
|
406
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputDir, '.github', 'workflows', 'deploy.yml'), workflowContent, 'utf-8');
|
|
407
|
+
}
|
|
408
|
+
core_1.logger.succeedSpinner('MCP created successfully!');
|
|
409
|
+
core_1.logger.section('Next steps', [
|
|
410
|
+
`1. cd ${outputDir}`,
|
|
411
|
+
'2. docker-compose up # Start with Docker',
|
|
412
|
+
'',
|
|
413
|
+
'Or for local development:',
|
|
414
|
+
'2. uv pip install -e .',
|
|
415
|
+
'3. python server.py',
|
|
416
|
+
'',
|
|
417
|
+
'Or use MCP Inspector:',
|
|
418
|
+
'2. uv pip install -e .',
|
|
419
|
+
'3. fastmcp dev server.py',
|
|
420
|
+
'',
|
|
421
|
+
'Add to Claude Code settings to use this MCP'
|
|
422
|
+
]);
|
|
423
|
+
core_1.logger.success(`✨ MCP "${name}" ready to use!`);
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
core_1.logger.failSpinner('Failed to create MCP');
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loginCommand = loginCommand;
|
|
7
|
+
const core_1 = require("@neural-tools/core");
|
|
8
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
+
async function loginCommand(options) {
|
|
10
|
+
core_1.logger.header('AI Toolkit License Management');
|
|
11
|
+
let licenseKey = options.key;
|
|
12
|
+
if (!licenseKey) {
|
|
13
|
+
const answers = await inquirer_1.default.prompt([
|
|
14
|
+
{
|
|
15
|
+
type: 'input',
|
|
16
|
+
name: 'licenseKey',
|
|
17
|
+
message: 'Enter your license key:',
|
|
18
|
+
validate: (input) => {
|
|
19
|
+
if (!input || input.trim().length === 0) {
|
|
20
|
+
return 'License key is required';
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
]);
|
|
26
|
+
licenseKey = answers.licenseKey;
|
|
27
|
+
}
|
|
28
|
+
if (!licenseKey) {
|
|
29
|
+
core_1.logger.error('License key is required');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
core_1.logger.startSpinner('Validating license...');
|
|
33
|
+
try {
|
|
34
|
+
// TODO: Validate license key with backend API
|
|
35
|
+
// For now, parse the key format: tier-email-signature
|
|
36
|
+
const parts = licenseKey.split('-');
|
|
37
|
+
if (parts.length < 2) {
|
|
38
|
+
throw new Error('Invalid license key format');
|
|
39
|
+
}
|
|
40
|
+
const tier = parts[0];
|
|
41
|
+
const email = parts[1];
|
|
42
|
+
// Validate tier
|
|
43
|
+
if (!Object.values(core_1.LicenseTier).includes(tier)) {
|
|
44
|
+
throw new Error('Invalid license tier');
|
|
45
|
+
}
|
|
46
|
+
// Save license
|
|
47
|
+
await core_1.licenseManager.saveLicense({
|
|
48
|
+
tier,
|
|
49
|
+
email,
|
|
50
|
+
key: licenseKey,
|
|
51
|
+
features: []
|
|
52
|
+
});
|
|
53
|
+
core_1.logger.succeedSpinner('License activated successfully!');
|
|
54
|
+
const license = await core_1.licenseManager.loadLicense();
|
|
55
|
+
core_1.logger.section('License Details', [
|
|
56
|
+
`Tier: ${license.tier.toUpperCase()}`,
|
|
57
|
+
`Email: ${license.email || 'N/A'}`,
|
|
58
|
+
`Status: Active`
|
|
59
|
+
]);
|
|
60
|
+
// Show available features based on tier
|
|
61
|
+
const features = getFeaturesByTier(tier);
|
|
62
|
+
core_1.logger.section('Available Features', features);
|
|
63
|
+
if (tier === core_1.LicenseTier.FREE) {
|
|
64
|
+
core_1.logger.newline();
|
|
65
|
+
core_1.logger.info('Upgrade to Pro for advanced features:');
|
|
66
|
+
core_1.logger.info('https://ai-toolkit.dev/pricing');
|
|
67
|
+
}
|
|
68
|
+
core_1.logger.success('✨ Ready to build!');
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
core_1.logger.failSpinner('License validation failed');
|
|
72
|
+
core_1.logger.error(error.message || 'Invalid license key');
|
|
73
|
+
core_1.logger.newline();
|
|
74
|
+
core_1.logger.info('Get a license at: https://ai-toolkit.dev/pricing');
|
|
75
|
+
core_1.logger.info('Or continue with free tier features');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function getFeaturesByTier(tier) {
|
|
79
|
+
const freeTier = [
|
|
80
|
+
'✓ MCP generation',
|
|
81
|
+
'✓ Claude commands',
|
|
82
|
+
'✓ Basic templates',
|
|
83
|
+
'✓ Local development'
|
|
84
|
+
];
|
|
85
|
+
const proTier = [
|
|
86
|
+
...freeTier,
|
|
87
|
+
'✓ Vector database integration',
|
|
88
|
+
'✓ Semantic caching',
|
|
89
|
+
'✓ Fine-tuning workflows',
|
|
90
|
+
'✓ Cloud deployment (AWS/GCP)',
|
|
91
|
+
'✓ Premium templates',
|
|
92
|
+
'✓ GitHub automation'
|
|
93
|
+
];
|
|
94
|
+
const enterpriseTier = [
|
|
95
|
+
...proTier,
|
|
96
|
+
'✓ White-label support',
|
|
97
|
+
'✓ Custom integrations',
|
|
98
|
+
'✓ Priority support',
|
|
99
|
+
'✓ SLA guarantee',
|
|
100
|
+
'✓ Team collaboration features'
|
|
101
|
+
];
|
|
102
|
+
switch (tier) {
|
|
103
|
+
case core_1.LicenseTier.FREE:
|
|
104
|
+
return freeTier;
|
|
105
|
+
case core_1.LicenseTier.PRO:
|
|
106
|
+
return proTier;
|
|
107
|
+
case core_1.LicenseTier.ENTERPRISE:
|
|
108
|
+
return enterpriseTier;
|
|
109
|
+
default:
|
|
110
|
+
return freeTier;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function statusCommand(): Promise<void>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.statusCommand = statusCommand;
|
|
4
|
+
const core_1 = require("@neural-tools/core");
|
|
5
|
+
async function statusCommand() {
|
|
6
|
+
core_1.logger.header('AI Toolkit Status');
|
|
7
|
+
try {
|
|
8
|
+
const license = await core_1.licenseManager.loadLicense();
|
|
9
|
+
core_1.logger.section('License Information', [
|
|
10
|
+
`Tier: ${license.tier.toUpperCase()}`,
|
|
11
|
+
`Email: ${license.email || 'N/A'}`,
|
|
12
|
+
`Status: ${license.expiresAt ? checkExpiration(license.expiresAt) : 'Active'}`
|
|
13
|
+
]);
|
|
14
|
+
// Check available features
|
|
15
|
+
const features = [
|
|
16
|
+
{ name: 'MCP Generation', key: 'mcp-generation' },
|
|
17
|
+
{ name: 'Claude Commands', key: 'claude-commands' },
|
|
18
|
+
{ name: 'Vector Database', key: 'vector-db' },
|
|
19
|
+
{ name: 'Semantic Cache', key: 'semantic-cache' },
|
|
20
|
+
{ name: 'Fine-tuning', key: 'fine-tuning' },
|
|
21
|
+
{ name: 'Cloud Deployment', key: 'cloud-deployment' },
|
|
22
|
+
{ name: 'GitHub Automation', key: 'github-automation' }
|
|
23
|
+
];
|
|
24
|
+
const featureStatus = await Promise.all(features.map(async (feature) => {
|
|
25
|
+
const available = await core_1.licenseManager.checkFeature(feature.key);
|
|
26
|
+
return `${available ? '✓' : '✗'} ${feature.name}`;
|
|
27
|
+
}));
|
|
28
|
+
core_1.logger.section('Feature Availability', featureStatus);
|
|
29
|
+
if (license.tier === core_1.LicenseTier.FREE) {
|
|
30
|
+
core_1.logger.newline();
|
|
31
|
+
core_1.logger.info('Unlock more features with Pro or Enterprise:');
|
|
32
|
+
core_1.logger.info('https://ai-toolkit.dev/pricing');
|
|
33
|
+
}
|
|
34
|
+
core_1.logger.newline();
|
|
35
|
+
core_1.logger.section('Quick Start', [
|
|
36
|
+
'Generate an MCP server:',
|
|
37
|
+
' ai-toolkit generate mcp github',
|
|
38
|
+
'',
|
|
39
|
+
'Generate a Claude command:',
|
|
40
|
+
' ai-toolkit generate command search-kb',
|
|
41
|
+
'',
|
|
42
|
+
'View all commands:',
|
|
43
|
+
' ai-toolkit --help'
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
core_1.logger.error('Failed to load license information');
|
|
48
|
+
core_1.logger.newline();
|
|
49
|
+
core_1.logger.info('Run "ai-toolkit login" to activate your license');
|
|
50
|
+
core_1.logger.info('Or continue with free tier features');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function checkExpiration(expiresAt) {
|
|
54
|
+
const expirationDate = new Date(expiresAt);
|
|
55
|
+
const now = new Date();
|
|
56
|
+
if (expirationDate < now) {
|
|
57
|
+
return 'Expired';
|
|
58
|
+
}
|
|
59
|
+
const daysUntilExpiration = Math.ceil((expirationDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
60
|
+
if (daysUntilExpiration <= 30) {
|
|
61
|
+
return `Active (expires in ${daysUntilExpiration} days)`;
|
|
62
|
+
}
|
|
63
|
+
return 'Active';
|
|
64
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { generateMCP } from './commands/generate-mcp';
|
|
2
|
+
export { generateCommand } from './commands/generate-command';
|
|
3
|
+
export { generateAgent } from './commands/generate-agent';
|
|
4
|
+
export { deployMCP } from './commands/deploy';
|
|
5
|
+
export { loginCommand } from './commands/login';
|
|
6
|
+
export { statusCommand } from './commands/status';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.statusCommand = exports.loginCommand = exports.deployMCP = exports.generateAgent = exports.generateCommand = exports.generateMCP = void 0;
|
|
4
|
+
var generate_mcp_1 = require("./commands/generate-mcp");
|
|
5
|
+
Object.defineProperty(exports, "generateMCP", { enumerable: true, get: function () { return generate_mcp_1.generateMCP; } });
|
|
6
|
+
var generate_command_1 = require("./commands/generate-command");
|
|
7
|
+
Object.defineProperty(exports, "generateCommand", { enumerable: true, get: function () { return generate_command_1.generateCommand; } });
|
|
8
|
+
var generate_agent_1 = require("./commands/generate-agent");
|
|
9
|
+
Object.defineProperty(exports, "generateAgent", { enumerable: true, get: function () { return generate_agent_1.generateAgent; } });
|
|
10
|
+
var deploy_1 = require("./commands/deploy");
|
|
11
|
+
Object.defineProperty(exports, "deployMCP", { enumerable: true, get: function () { return deploy_1.deployMCP; } });
|
|
12
|
+
var login_1 = require("./commands/login");
|
|
13
|
+
Object.defineProperty(exports, "loginCommand", { enumerable: true, get: function () { return login_1.loginCommand; } });
|
|
14
|
+
var status_1 = require("./commands/status");
|
|
15
|
+
Object.defineProperty(exports, "statusCommand", { enumerable: true, get: function () { return status_1.statusCommand; } });
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@neural-tools/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Neural Tools - Generate MCPs, Claude commands, and AI workflows",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"neural-tools": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"license": "SEE LICENSE IN ../../LICENSE.md",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/yourusername/ai-toolkit.git",
|
|
17
|
+
"directory": "packages/cli"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"commander": "^12.0.0",
|
|
21
|
+
"inquirer": "^9.2.12",
|
|
22
|
+
"execa": "^8.0.1",
|
|
23
|
+
"fs-extra": "^11.2.0",
|
|
24
|
+
"globby": "^14.0.0",
|
|
25
|
+
"picocolors": "^1.0.0",
|
|
26
|
+
"@neural-tools/core": "0.1.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/fs-extra": "^11.0.4",
|
|
30
|
+
"@types/inquirer": "^9.0.7",
|
|
31
|
+
"@types/node": "^20.11.5",
|
|
32
|
+
"typescript": "^5.3.3"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc && chmod +x dist/cli.js",
|
|
39
|
+
"dev": "tsc --watch",
|
|
40
|
+
"clean": "rm -rf dist",
|
|
41
|
+
"test": "echo 'Tests coming soon'"
|
|
42
|
+
}
|
|
43
|
+
}
|