@noanswer/context-compose
Version:
Orchestrate complex AI interactions with Context Compose. A powerful CLI and server for building, validating, and managing context for large language models using the Model Context Protocol (MCP).
81 lines • 3.54 kB
JavaScript
import { join } from 'node:path';
import * as z from 'zod';
import { StartContextToolSchema } from '../../schemas/start-context.js';
import { InvalidContextError } from '../errors.js';
import { combinePrompts, processContextSections, } from '../utils/prompt-combiner.js';
import { SecuritySchemas, defaultPathValidator } from '../utils/security.js';
import { readYamlFile } from '../utils/yaml.js';
/**
* Reads the main context file (e.g., feature-context.yaml) asynchronously.
*/
async function readContextFile(projectRoot, contextName) {
// Validate inputs for security
SecuritySchemas.projectRoot.parse(projectRoot);
SecuritySchemas.contextName.parse(contextName);
const contextFilePath = join(projectRoot, '.contextcompose', `${contextName}-context.yaml`);
// Validate path is within project root
const validatedPath = defaultPathValidator.validateContextPath(contextFilePath, projectRoot);
const context = await readYamlFile(validatedPath);
if (context.kind !== 'context') {
throw new InvalidContextError(`Invalid context file kind: ${context.kind}. Expected 'context'.`, { contextName, kind: context.kind });
}
return context;
}
/**
* Main tool logic for starting a context.
* It reads the specified context file and constructs the initial prompt.
*/
export async function executeStartContext(input) {
try {
// 1. Read the main context file
const contextYaml = await readContextFile(input.projectRoot, input.contextName);
// 2. Process all referenced files (personas, rules, etc.)
const processedSections = await processContextSections(input.projectRoot, contextYaml.context, input.enhancedPrompt);
// 3. Combine prompts into a single string
const combinedPrompt = combinePrompts(contextYaml, processedSections, input.enhancedPrompt);
return {
success: true,
message: `Context '${input.contextName}' started successfully.`,
contextName: input.contextName,
combinedPrompt,
files: contextYaml.context,
};
}
catch (error) {
return {
success: false,
message: `Failed to start context: ${error instanceof Error ? error.message : String(error)}`,
contextName: input.contextName,
};
}
}
/**
* Validates the input arguments for the Start Context tool and executes the core logic.
* This function serves as the main entry point for the MCP tool, ensuring
* that the provided arguments are valid before proceeding.
* It reads the specified context file and constructs the initial prompt.
*/
export async function executeStartContextTool(args) {
try {
const validatedArgs = StartContextToolSchema.parse(args);
return await executeStartContext(validatedArgs);
}
catch (error) {
if (error instanceof z.ZodError) {
const errorMessages = error.errors.map((e) => e.message).join(', ');
return {
success: false,
message: `Invalid input: ${errorMessages}`,
contextName: args?.contextName || '',
};
}
// Handle other errors (e.g., from executeStartContext)
const errorMessage = error instanceof Error ? error.message : String(error);
return {
success: false,
message: `Failed to start context: ${errorMessage}`,
contextName: args?.contextName || '',
};
}
}
//# sourceMappingURL=start-context.js.map