Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs/cli/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Templates are organized into categories:
- `devops` - DevOps tools and automation
- `mobile` - Mobile app projects
- `tools` - CLI tools and utilities
- `seo` - SEO and Answer Engine Optimization toolkits

## Examples

Expand Down
15 changes: 6 additions & 9 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#!/usr/bin/env node

import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import chalk from 'chalk';
import { Command } from 'commander';
import { authCommand } from './commands/auth.js';
Expand All @@ -19,13 +16,10 @@ import { sourceCommand } from './commands/source.js';
import { templateCommand } from './commands/template.js';
import { startMcpServer } from './mcp/server.js';
import { formatPresetsHelp, getPresetNames } from './presets/index.js';
import { getPackageVersion } from './utils/version.js';
import { runIdeaMode, runWizard } from './wizard/index.js';

// Read version from package.json dynamically
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
const VERSION = packageJson.version;
const VERSION = getPackageVersion();

const program = new Command();

Expand Down Expand Up @@ -264,7 +258,10 @@ program
program
.command('template [action] [args...]')
.description('Browse and use project templates from ralph-templates')
.option('--category <name>', 'Filter by category (web-dev, blockchain, devops, mobile, tools)')
.option(
'--category <name>',
'Filter by category (web-dev, blockchain, devops, mobile, tools, seo)'
)
.option('--refresh', 'Force refresh the cache')
.option('--auto', 'Skip confirmation prompts')
.option('--output-dir <path>', 'Directory to create the project in')
Expand Down
2 changes: 1 addition & 1 deletion src/commands/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ ${chalk.bold('Commands:')}
browse Interactive template browser

${chalk.bold('Options:')}
--category <name> Filter by category (web-dev, blockchain, devops, mobile, tools)
--category <name> Filter by category (web-dev, blockchain, devops, mobile, tools, seo)
--refresh Force refresh the cache
--auto Skip confirmation prompts
--output-dir <path> Directory to create the project in
Expand Down
133 changes: 126 additions & 7 deletions src/mcp/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,17 @@ export function getPrompts(): Prompt[] {
},
{
name: 'fetch_and_build',
description: 'Fetch a spec from a source and start building',
description:
'Fetch a spec from an external source (GitHub, Linear, Notion, Figma) and start building',
arguments: [
{
name: 'source',
description: 'Source to fetch from (url, github, todoist, linear, notion)',
description: 'Source to fetch from (url, github, linear, notion, figma)',
required: true,
},
{
name: 'identifier',
description: 'Source identifier (URL, project name, etc.)',
description: 'Source identifier (URL, project name, issue number, Figma file URL, etc.)',
required: true,
},
{
Expand All @@ -64,6 +65,62 @@ export function getPrompts(): Prompt[] {
},
],
},
{
name: 'figma_to_code',
description:
'Extract a Figma design and build it as code. Supports design specs, tokens, components, and content extraction.',
arguments: [
{
name: 'figma_url',
description: 'Figma file or frame URL',
required: true,
},
{
name: 'framework',
description:
'Target framework: react, vue, svelte, astro, nextjs, nuxt, html (default: react)',
required: false,
},
{
name: 'mode',
description:
'Extraction mode: spec (full design spec), tokens (design tokens as CSS/Tailwind), components (component code), content (text/IA extraction)',
required: false,
},
{
name: 'path',
description: 'Project directory to build in',
required: false,
},
],
},
{
name: 'batch_issues',
description:
'Process multiple GitHub or Linear issues automatically in sequence. Each issue becomes a task with its own branch, commits, and PR.',
arguments: [
{
name: 'source',
description: 'Issue source: github or linear',
required: true,
},
{
name: 'project',
description: 'GitHub repo (owner/repo) or Linear project name',
required: true,
},
{
name: 'label',
description: 'Filter issues by label (e.g., "good first issue", "bug", "enhancement")',
required: false,
},
{
name: 'path',
description: 'Project directory path',
required: false,
},
],
},
];
}

Expand Down Expand Up @@ -150,20 +207,82 @@ Show me where we are!`,
type: 'text',
text: `Please fetch a spec and build a project from it.

Source: ${args?.source || '(specify source)'}
Source: ${args?.source || '(specify source: github, linear, notion, or figma)'}
Identifier: ${args?.identifier || '(specify identifier)'}
Path: ${cwd}

1. First, initialize Ralph Playbook at the path if needed
2. Use ralph_run with the --from option to fetch the spec and start building
3. Monitor progress and help resolve any issues
1. First, use ralph_fetch_spec to preview the spec content
2. Initialize Ralph Playbook at the path if needed
3. Use ralph_run with the --from option to fetch the spec and start building
4. Monitor progress and help resolve any issues

Let's build it!`,
},
},
],
};

case 'figma_to_code': {
const framework = args?.framework || 'react';
const displayFramework = framework.charAt(0).toUpperCase() + framework.slice(1);
return {
description: 'Convert Figma design to code',
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Please extract a Figma design and build it as code.

Figma URL: ${args?.figma_url || '(specify Figma file URL)'}
Framework: ${framework}
Mode: ${args?.mode || 'spec'}
Path: ${cwd}

1. First, use ralph_fetch_spec with source "figma" to extract the design:
- Use mode "${args?.mode || 'spec'}" to get ${args?.mode === 'tokens' ? 'design tokens' : args?.mode === 'components' ? 'component structure' : args?.mode === 'content' ? 'text content and IA' : 'the full design specification'}
2. Review the extracted spec — check colors, typography, spacing, and component structure
3. Initialize Ralph Playbook if needed, then use ralph_run to build the ${displayFramework} implementation
4. The agent will iterate until the UI matches the design spec, running validation between iterations

Let's bring this design to life!`,
},
},
],
};
}

case 'batch_issues':
return {
description: 'Process multiple issues automatically',
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Please process multiple issues from ${args?.source || '(github or linear)'} automatically.

Source: ${args?.source || '(specify: github or linear)'}
Project: ${args?.project || '(specify repo or project name)'}
${args?.label ? `Label filter: ${args.label}` : 'Label: (all issues)'}
Path: ${cwd}

1. Use ralph_run with auto mode to batch-process issues from ${args?.source || 'the source'}:
- Set from="${args?.source || '(github or linear)'}" and project="${args?.project || '(specify)'}"
${args?.label ? `- Filter by label: "${args.label}"` : ''}
- Enable auto=true, commit=true, and validate=true
- Each issue gets its own branch
- Code changes are validated and auto-committed
- A PR is created for each completed issue
2. Monitor progress across all issues
3. If an individual issue fails, note the failure and continue to the next one

Let's batch process these issues!`,
},
},
],
};

default:
throw new Error(`Unknown prompt: ${name}`);
}
Expand Down
16 changes: 16 additions & 0 deletions src/mcp/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ export async function getResources(): Promise<Resource[]> {
}
}

// Activity log
const activityPath = join(cwd, '.ralph', 'activity.md');
if (existsSync(activityPath)) {
resources.push({
uri: 'ralph://project/activity',
name: 'Activity Log',
description:
'Loop execution history with timing, cost data, and task outcomes (.ralph/activity.md)',
mimeType: 'text/markdown',
});
}

return resources;
}

Expand Down Expand Up @@ -105,6 +117,10 @@ export async function handleResourceRead(uri: string): Promise<{
filePath = join(cwd, 'PROMPT_plan.md');
break;

case 'activity':
filePath = join(cwd, '.ralph', 'activity.md');
break;

default:
// Handle specs
if (resourcePath.startsWith('specs/')) {
Expand Down
3 changes: 2 additions & 1 deletion src/mcp/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ListToolsRequestSchema,
ReadResourceRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { getPackageVersion } from '../utils/version.js';
import { getPrompts, handleGetPrompt } from './prompts.js';
import { getResources, handleResourceRead } from './resources.js';
import { getTools, handleToolCall } from './tools.js';
Expand All @@ -19,7 +20,7 @@ export function createMcpServer(): Server {
const server = new Server(
{
name: 'ralph-starter',
version: '0.1.0',
version: getPackageVersion(),
},
{
capabilities: {
Expand Down
Loading
Loading