@grubtech/integration-agent
Version:
One-command installer that sets up the complete Grubtech Integration Agent (MCP server + AI agent personas) for Claude Code to help developers build restaurant and POS integrations.
331 lines (313 loc) • 15.4 kB
JavaScript
import { promises as fs } from 'fs';
import { join, dirname } from 'path';
import { homedir } from 'os';
import { createRequire } from 'module';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
/**
* Initializes the Grubtech Integration Agent
*
* This command sets up everything needed to use the MCP server with Claude Code:
* 1. Verifies Claude Code is installed (exits with error if not found)
* 2. Creates cache directory for storing scraped documentation
* 3. Registers MCP server using 'claude mcp add' command (requires claude CLI in PATH)
* 4. Installs agent persona YAML files to project's .claude/grubtech/agents/ directory as subagents
*
* Users only need to run this once: npx @grubtech/integration-agent init
*/
export async function initCommand() {
console.log('Initializing Grubtech Integration Agent...\n');
// Step 1: Verify Claude Code is installed
console.log('[1/5] Checking for Claude Code installation...');
const claudeConfigPath = getClaudeConfigPath();
try {
await fs.access(claudeConfigPath);
console.log(' ✓ Claude Code found\n');
}
catch {
console.error(' ✗ Claude Code is not installed!\n');
console.error('This tool requires Claude Code to be installed on your system.\n');
console.error('Download Claude Code from: https://claude.ai/download\n');
console.error('After installing Claude Code, run this command again:');
console.error(' npx @grubtech/integration-agent init\n');
process.exit(1);
}
// Step 2: Create cache directory (global) and examples directory (local)
// Cache: Global storage for scraped Grubtech documentation (avoids repeated downloads)
// Examples: Local project-specific API and webhook examples
console.log('[2/5] Creating cache directory...');
const grubtechDir = join(homedir(), '.grubtech');
const cacheDir = join(grubtechDir, 'cache');
await fs.mkdir(join(cacheDir, 'docs'), { recursive: true });
console.log(' ✓ Cache directory created at ~/.grubtech/cache/\n');
// Step 3: Install Grubtech Integration (BMAD-METHOD pattern)
console.log('[3/5] Installing Grubtech Integration files...');
const grubtechIntegrationDir = join(process.cwd(), '.grubtech-integration');
await installGrubtechIntegration(grubtechIntegrationDir);
// Step 4: Configure MCP server in Claude Code using the claude CLI
// This registers the MCP server with identifier 'grubtech-integration-support'
// Syntax: claude mcp add --transport stdio <name> -- <command> [args...]
console.log('[4/5] Configuring MCP server...');
// First, try to remove existing MCP server (ignore errors if it doesn't exist)
try {
await execAsync('claude mcp remove grubtech-integration-support');
console.log(' ✓ Removed existing MCP server configuration');
}
catch {
// Server doesn't exist, that's fine
}
// Use node to import the package directly (works reliably on all platforms)
// This avoids npx bin entry issues on Windows with scoped packages
const mcpCommand = `claude mcp add --transport stdio grubtech-integration-support -- node --input-type=module --eval "await import('@grubtech/integration-mcp-server')"`;
try {
await execAsync(mcpCommand);
console.log(' ✓ MCP server registered with Claude Code\n');
}
catch (error) {
// Check if it's just an "already exists" error
if (error.message.includes('already exists')) {
console.log(' ⚠ MCP server already configured (skipping)\n');
}
else {
console.error(' ✗ Failed to register MCP server!\n');
console.error('The "claude" CLI command is not available or failed to execute.\n');
console.error('Please ensure:');
console.error(' 1. Claude Code is running');
console.error(' 2. The "claude" command is available in your PATH');
console.error(' 3. You have the latest version of Claude Code\n');
console.error('Error details:', error.message, '\n');
console.error('For manual setup, see: https://docs.claude.com/en/docs/claude-code/mcp\n');
console.error('Continuing with agent persona installation...\n');
}
}
// Step 5: Link to Claude Code
console.log('[5/5] Linking agents and commands to Claude Code...');
await linkToClaudeCode(process.cwd(), grubtechIntegrationDir);
// Step 6: Display success message
console.log('\n✓ Setup complete!\n');
console.log('Installed components:');
console.log(' • MCP Server: @grubtech/integration-mcp-server');
console.log(' • Grubtech Integration: ./.grubtech-integration/');
console.log(' - agents/ (3 AI agents: BA, Developer, Assistant)');
console.log(' - examples/ (43 API & webhook examples)');
console.log(' - postman-collections/ (3 collections + guide)');
console.log(' - commands/ (3 slash commands)');
console.log(' - docs/ (getting started guide)');
console.log(' • Claude Code: .claude/agents/ and .claude/commands/ (linked)\n');
console.log('Next steps:');
console.log(' 1. Restart Claude Code');
console.log(' 2. Use slash commands to activate agents:');
console.log(' /grubtech-ba - Business Analyst (planning, requirements)');
console.log(' /grubtech-dev - Developer (technical implementation)');
console.log(' /grubtech-assistant - Integration Assistant (technical support, architecture)');
console.log(' 3. Or ask: "How do I authenticate with Grubtech APIs?"\n');
}
/**
* Installs Grubtech Integration following BMAD-METHOD pattern
*
* Creates structured directory: grubtech-integration/
* - agents/ - AI agent personas
* - examples/ - API & webhook examples
* - commands/ - Slash commands
* - docs/ - Documentation
*/
async function installGrubtechIntegration(baseDir) {
try {
// Use Node's module resolution to find the integration-personas package
const require = createRequire(import.meta.url);
const personasPackagePath = require.resolve('@grubtech/integration-personas/package.json');
const personasSourceDir = dirname(personasPackagePath);
// Create directory structure
await fs.mkdir(join(baseDir, 'agents'), { recursive: true });
await fs.mkdir(join(baseDir, 'examples'), { recursive: true });
await fs.mkdir(join(baseDir, 'postman-collections'), { recursive: true });
await fs.mkdir(join(baseDir, 'commands'), { recursive: true });
await fs.mkdir(join(baseDir, 'docs'), { recursive: true });
// Install agents
const agentFiles = [
{ source: 'ba-agent.md', target: 'business-analyst.md', name: 'Business Analyst' },
{ source: 'developer-agent.md', target: 'developer.md', name: 'Developer' },
{ source: 'integration-assistant-agent.md', target: 'integration-assistant.md', name: 'Integration Assistant' },
];
for (const agent of agentFiles) {
await fs.copyFile(join(personasSourceDir, agent.source), join(baseDir, 'agents', agent.target));
}
console.log(' ✓ Agents installed (3 files)');
// Install commands
const commandFiles = [
{ source: 'business-analyst-command.md', target: 'grubtech-ba.md' },
{ source: 'developer-command.md', target: 'grubtech-dev.md' },
{ source: 'integration-assistant-command.md', target: 'grubtech-assistant.md' },
];
for (const cmd of commandFiles) {
await fs.copyFile(join(personasSourceDir, cmd.source), join(baseDir, 'commands', cmd.target));
}
console.log(' ✓ Commands installed (3 files)');
// Install examples
const examplesSourceDir = join(personasSourceDir, 'examples');
await copyRecursive(examplesSourceDir, join(baseDir, 'examples'));
console.log(' ✓ Examples installed (43 files across 3 API suites)');
// Install Postman collections
const postmanSourceDir = join(personasSourceDir, 'postman-collections');
await copyRecursive(postmanSourceDir, join(baseDir, 'postman-collections'));
console.log(' ✓ Postman collections installed (3 webhook collections + testing guide)');
// Create README in docs/
const readme = `# Grubtech Integration
This directory contains everything you need to integrate with Grubtech APIs.
## Structure
- **agents/** - AI agent personas for Claude Code
- business-analyst.md - Requirements gathering and planning
- developer.md - Code generation and implementation
- integration-assistant.md - Technical support and architecture
- **examples/** - Complete API & webhook examples (43 total)
- order-platform/ - For food aggregators (6 APIs + 9 webhooks)
- pos/ - For POS systems (13 APIs + 6 webhooks)
- delivery/ - For logistics providers (1 API + 3 webhooks)
- README.md - Navigation guide and documentation
- **postman-collections/** - Webhook testing collections (RECOMMENDED)
- postman-order-platform-webhooks.json - Order Platform webhooks collection
- postman-pos-webhooks.json - POS webhooks collection
- postman-delivery-webhooks.json - Delivery webhooks collection
- README.md - Complete guide for testing webhooks with Postman mock servers
- **commands/** - Slash commands for Claude Code
- /grubtech-ba - Quick access to Business Analyst
- /grubtech-dev - Quick access to Developer
- /grubtech-assistant - Quick access to Integration Assistant
## Getting Started
1. **Test Webhooks First** (RECOMMENDED): Use Postman mock servers to see actual webhook payloads
- See: postman-collections/README.md for step-by-step guide
- Import the collection for your integration type
- Create mock server and register URLs in Developer Portal
- See exact webhook payloads before writing any code
2. **Use AI Agents**: Restart Claude Code and use slash commands
- /grubtech-ba - For planning and requirements
- /grubtech-dev - For code generation
- /grubtech-assistant - For technical support
3. **Reference Examples**: All APIs and webhooks have complete examples
- See examples/ directory for cURL commands and payloads
## Examples
All API calls and webhooks have complete examples with:
- cURL commands
- Request/response payloads
- Authentication headers
- Implementation notes
- Field descriptions
See examples/README.md for full documentation.
## Postman Collections
Test webhook configurations BEFORE coding using Postman mock servers:
- Zero infrastructure required
- See real webhook payloads
- Validate Developer Portal configuration
- Plan database schema based on actual data
See postman-collections/README.md for complete testing guide.
## Resources
- Developer Portal: https://developer.grubtech.com
- API Documentation: https://docs.grubtech.io
- Support: support@grubtech.com
`;
await fs.writeFile(join(baseDir, 'docs', 'README.md'), readme);
console.log(' ✓ Documentation created');
// Write version file
await fs.writeFile(join(baseDir, '.grubtech-version'), '1.0.0');
console.log(' ✓ Version tracking initialized\n');
}
catch (error) {
console.error(' ✗ Failed to install Grubtech Integration');
console.error(` Error: ${error.message}\n`);
throw error;
}
}
/**
* Recursively copies a directory
*/
async function copyRecursive(source, target) {
await fs.mkdir(target, { recursive: true });
const entries = await fs.readdir(source, { withFileTypes: true });
for (const entry of entries) {
const sourcePath = join(source, entry.name);
const targetPath = join(target, entry.name);
if (entry.isDirectory()) {
await copyRecursive(sourcePath, targetPath);
}
else {
await fs.copyFile(sourcePath, targetPath);
}
}
}
/**
* Links Grubtech Integration files to Claude Code directories
*
* Creates copies in .claude/ directories so Claude Code can access them:
* - Agents from grubtech-integration/agents/ -> .claude/agents/
* - Commands from grubtech-integration/commands/ -> .claude/commands/
*/
async function linkToClaudeCode(projectPath, grubtechDir) {
try {
// Create .claude directories
const claudeAgentsDir = join(projectPath, '.claude', 'agents');
const claudeCommandsDir = join(projectPath, '.claude', 'commands');
await fs.mkdir(claudeAgentsDir, { recursive: true });
await fs.mkdir(claudeCommandsDir, { recursive: true });
// Link agents
const agentMappings = [
{ source: 'business-analyst.md', target: 'grubtech-business-analyst.md', name: 'Business Analyst' },
{ source: 'developer.md', target: 'grubtech-developer.md', name: 'Developer' },
{ source: 'integration-assistant.md', target: 'grubtech-integration-assistant.md', name: 'Integration Assistant' },
];
for (const agent of agentMappings) {
const sourcePath = join(grubtechDir, 'agents', agent.source);
const targetPath = join(claudeAgentsDir, agent.target);
try {
await fs.copyFile(sourcePath, targetPath);
console.log(` ✓ ${agent.name} agent`);
}
catch (error) {
console.warn(` ⚠ Failed to link ${agent.name}: ${error.message}`);
}
}
// Link commands
const commandMappings = [
{ source: 'grubtech-ba.md', name: '/grubtech-ba' },
{ source: 'grubtech-dev.md', name: '/grubtech-dev' },
{ source: 'grubtech-assistant.md', name: '/grubtech-assistant' },
];
for (const cmd of commandMappings) {
const sourcePath = join(grubtechDir, 'commands', cmd.source);
const targetPath = join(claudeCommandsDir, cmd.source);
try {
await fs.copyFile(sourcePath, targetPath);
console.log(` ✓ ${cmd.name}`);
}
catch (error) {
console.warn(` ⚠ Failed to link ${cmd.name}: ${error.message}`);
}
}
console.log(' ✓ All links created successfully\n');
}
catch (error) {
console.error(' ✗ Failed to link to Claude Code');
console.error(` Error: ${error.message}\n`);
throw error;
}
}
/**
* Gets the Claude Code configuration directory path
*
* Different operating systems store Claude config in different locations:
* - Windows: %APPDATA%\Claude\config
* - macOS: ~/Library/Application Support/Claude/config
* - Linux: ~/.config/claude
*/
function getClaudeConfigPath() {
const home = homedir();
switch (process.platform) {
case 'win32':
return join(home, 'AppData', 'Roaming', 'Claude', 'config');
case 'darwin':
return join(home, 'Library', 'Application Support', 'Claude', 'config');
default:
return join(home, '.config', 'claude');
}
}
//# sourceMappingURL=init-command.js.map