Skip to content
Open
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_modules/
out/
dist/
*.vsix
*.tsbuildinfo

# Generated files
*.generated.ts
Expand Down
31 changes: 31 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"displayName": "Claude Code Workflow Studio",
"description": "Visual Workflow Editor for Claude Code, GitHub Copilot, and more AI agents",
"version": "3.26.0",
"private": true,
"workspaces": [
"packages/*"
],
"publisher": "breaking-brake",
"icon": "resources/icon.png",
"repository": {
Expand Down Expand Up @@ -90,7 +94,10 @@
"vscode:prepublish": "npm run build",
"generate:toon": "npx tsx scripts/generate-toon-schema.ts",
"generate:editing-flow": "npx tsx scripts/generate-editing-flow.ts",
"build": "npm run generate:toon && npm run generate:editing-flow && npm run build:webview && npm run build:extension",
"build": "npm run build:core && npm run generate:toon && npm run generate:editing-flow && npm run build:webview && npm run build:extension",
"build:core": "npm run build -w @cc-wf-studio/core",
"build:vscode": "npm run build:core && npm run generate:toon && npm run generate:editing-flow && npm run build:webview && npm run build:extension",
"build:electron": "npm run build:core && npm run build:webview && npm run build -w @cc-wf-studio/electron",
"build:dev": "npm run build:webview:dev && npm run build:extension:dev",
"build:webview": "cd src/webview && npm run build",
"build:webview:dev": "cd src/webview && npm run build:dev",
Expand Down
32 changes: 32 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@cc-wf-studio/core",
"version": "3.26.0",
"private": true,
"license": "AGPL-3.0-or-later",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"bin": {
"cc-wf-mcp-server": "./dist/cli/mcp-server-cli.js"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc -p tsconfig.json",
"clean": "rm -rf dist"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.26.0",
"@toon-format/toon": "^2.1.0",
"nano-spawn": "^2.0.0",
"smol-toml": "^1.6.0"
},
"devDependencies": {
"typescript": "^5.3.0",
"@types/node": "^25.0.3"
}
}
25 changes: 25 additions & 0 deletions packages/core/src/adapters/console-logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Console Logger Implementation
*
* ILogger implementation using console.log/warn/error.
* Used by Electron and CLI headless mode.
*/

import type { ILogger } from '../interfaces/logger.js';

export class ConsoleLogger implements ILogger {
info(message: string, data?: unknown): void {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] [INFO] ${message}`, data ?? '');
}

warn(message: string, data?: unknown): void {
const timestamp = new Date().toISOString();
console.warn(`[${timestamp}] [WARN] ${message}`, data ?? '');
}

error(message: string, data?: unknown): void {
const timestamp = new Date().toISOString();
console.error(`[${timestamp}] [ERROR] ${message}`, data ?? '');
}
}
54 changes: 54 additions & 0 deletions packages/core/src/adapters/node-file-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Node.js File System Implementation
*
* IFileSystem implementation using node:fs/promises.
* Used by Electron and CLI headless mode.
*/

import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import type { IFileSystem } from '../interfaces/file-system.js';

export class NodeFileSystem implements IFileSystem {
async readFile(filePath: string): Promise<string> {
return fs.readFile(filePath, 'utf-8');
}

async writeFile(filePath: string, content: string): Promise<void> {
const dir = path.dirname(filePath);
await fs.mkdir(dir, { recursive: true });
await fs.writeFile(filePath, content, 'utf-8');
}

async fileExists(filePath: string): Promise<boolean> {
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}

async createDirectory(dirPath: string): Promise<void> {
await fs.mkdir(dirPath, { recursive: true });
}

async readDirectory(
dirPath: string
): Promise<Array<{ name: string; isFile: boolean; isDirectory: boolean }>> {
const entries = await fs.readdir(dirPath, { withFileTypes: true });
return entries.map((entry) => ({
name: entry.name,
isFile: entry.isFile(),
isDirectory: entry.isDirectory(),
}));
}

async stat(filePath: string): Promise<{ isFile: boolean; isDirectory: boolean }> {
const stats = await fs.stat(filePath);
return {
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
};
}
}
57 changes: 57 additions & 0 deletions packages/core/src/cli/mcp-server-cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env node
/**
* CC Workflow Studio - Standalone MCP Server CLI
*
* Runs the MCP server in headless mode, operating directly on workflow JSON files.
* No UI required — AI agents can create and edit workflows via MCP tools.
*
* Usage:
* npx @cc-wf-studio/core mcp-server ./path/to/workflow.json
* npx @cc-wf-studio/core mcp-server (uses default .vscode/workflows/workflow.json)
*/

import * as path from 'node:path';
import { ConsoleLogger } from '../adapters/console-logger.js';
import { NodeFileSystem } from '../adapters/node-file-system.js';
import { FileSystemWorkflowProvider } from '../services/fs-workflow-provider.js';
import { setLogger } from '../services/logger-holder.js';
import { McpServerManager } from '../services/mcp-server-service.js';

async function main(): Promise<void> {
const logger = new ConsoleLogger();
setLogger(logger);

const workflowPath =
process.argv[2] || path.join(process.cwd(), '.vscode', 'workflows', 'workflow.json');
const resolvedPath = path.resolve(workflowPath);

logger.info(`CC Workflow Studio - Headless MCP Server`);
logger.info(`Workflow file: ${resolvedPath}`);

const fs = new NodeFileSystem();
const manager = new McpServerManager();

// Set up headless mode with filesystem provider
manager.setWorkflowProvider(new FileSystemWorkflowProvider(fs, resolvedPath));

// Start the MCP server
const port = await manager.start(process.cwd());

logger.info(`MCP Server running on http://127.0.0.1:${port}/mcp`);
logger.info(`Press Ctrl+C to stop`);

// Handle graceful shutdown
const shutdown = async (): Promise<void> => {
logger.info('Shutting down MCP server...');
await manager.stop();
process.exit(0);
};

process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
}

main().catch((error) => {
console.error('Failed to start MCP server:', error);
process.exit(1);
});
Loading