@stackmemoryai/stackmemory
Version:
Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.
405 lines (402 loc) • 13 kB
JavaScript
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import {
RecursiveAgentOrchestrator
} from "./recursive-agent-orchestrator.js";
import {
ClaudeSkillsManager
} from "./claude-skills.js";
import { logger } from "../core/monitoring/logger.js";
class UnifiedRLMOrchestrator {
rlmOrchestrator;
skillsManager;
skillMappings;
constructor(frameManager, dualStackManager, contextRetriever, taskStore, skillContext) {
this.rlmOrchestrator = new RecursiveAgentOrchestrator(
frameManager,
dualStackManager,
contextRetriever,
taskStore
);
this.skillsManager = new ClaudeSkillsManager(skillContext);
this.skillMappings = this.initializeSkillMappings();
logger.info("Unified RLM Orchestrator initialized with RLM-first routing");
}
/**
* Initialize skill to RLM agent mappings
*/
initializeSkillMappings() {
const mappings = /* @__PURE__ */ new Map();
mappings.set("handoff", {
skillName: "handoff",
primaryAgent: "context",
secondaryAgents: ["planning"],
taskTemplate: "Prepare comprehensive handoff to {targetUser}: {message}. Extract relevant context, identify dependencies, and create actionable items.",
defaultOptions: {
maxParallel: 3,
reviewStages: 1,
shareContextRealtime: true
},
preprocessor: (args, options) => ({
task: `Handoff to ${args[0]}: ${args[1]}`,
context: {
targetUser: args[0],
message: args[1],
priority: options.priority || "medium",
frames: options.frames || []
}
}),
postprocessor: (result) => ({
success: result.success,
message: `Handoff ${result.success ? "completed" : "failed"}`,
data: result.rootNode.result
})
});
mappings.set("checkpoint", {
skillName: "checkpoint",
primaryAgent: "context",
secondaryAgents: ["code"],
taskTemplate: "Create recovery checkpoint: {description}. Capture current state, identify risky operations, and backup critical files.",
defaultOptions: {
maxParallel: 2,
reviewStages: 0,
verboseLogging: false
},
preprocessor: (args, options) => ({
task: `${args[0]} checkpoint: ${args[1]}`,
context: {
operation: args[0],
description: args[1],
...options
}
})
});
mappings.set("dig", {
skillName: "dig",
primaryAgent: "context",
taskTemplate: "Deep archaeological search: {query}. Analyze patterns, extract decisions, and build timeline.",
defaultOptions: {
maxParallel: 1,
maxTokensPerAgent: 5e4,
reviewStages: 0
},
preprocessor: (args, options) => ({
task: `Archaeological dig: ${args[0]}`,
context: {
query: args[0],
depth: options.depth || "30days",
patterns: options.patterns,
decisions: options.decisions,
timeline: options.timeline
}
})
});
mappings.set("lint", {
skillName: "lint",
primaryAgent: "linting",
secondaryAgents: ["improve"],
taskTemplate: "Comprehensive linting of {path}: Check syntax, types, formatting, security, performance, and dead code. Provide fixes.",
defaultOptions: {
maxParallel: 1,
reviewStages: 0,
verboseLogging: true
},
preprocessor: (args, options) => ({
task: `Lint ${args[0] || "current directory"}`,
context: {
path: args[0] || process.cwd(),
fix: options.fix,
focus: options.security ? "security" : options.performance ? "performance" : "all"
}
}),
postprocessor: (result) => {
const lintingNode = this.findNodeByAgent(result.rootNode, "linting");
return {
success: result.success,
message: `Found ${result.issuesFound} issues, fixed ${result.issuesFixed}`,
data: {
issues: lintingNode?.result?.issues || [],
fixes: lintingNode?.result?.fixes || [],
stats: {
found: result.issuesFound,
fixed: result.issuesFixed,
duration: result.duration
}
}
};
}
});
mappings.set("test", {
skillName: "test",
primaryAgent: "testing",
secondaryAgents: ["code", "review"],
taskTemplate: "Generate comprehensive {testMode} tests for {target}. Ensure high coverage and meaningful assertions.",
defaultOptions: {
maxParallel: 3,
testGenerationMode: "all",
reviewStages: 2,
qualityThreshold: 0.9
},
preprocessor: (args, options) => ({
task: `Generate tests for ${args[0] || "project"}`,
context: {
target: args[0] || process.cwd(),
testMode: options.mode || "all",
coverage: options.coverage || "high"
}
})
});
mappings.set("review", {
skillName: "review",
primaryAgent: "review",
secondaryAgents: ["improve", "testing"],
taskTemplate: "Multi-stage code review of {target}. Analyze architecture, quality, performance, security. Suggest improvements.",
defaultOptions: {
maxParallel: 2,
reviewStages: 3,
qualityThreshold: 0.85,
verboseLogging: true
},
preprocessor: (args, options) => ({
task: `Review code in ${args[0] || "project"}`,
context: {
target: args[0] || process.cwd(),
focus: options.focus || "all",
autofix: options.fix || false
}
})
});
mappings.set("refactor", {
skillName: "refactor",
primaryAgent: "code",
secondaryAgents: ["review", "improve", "testing"],
taskTemplate: "Refactor {target}: Improve architecture, reduce complexity, enhance maintainability. Preserve functionality.",
defaultOptions: {
maxParallel: 4,
reviewStages: 2,
qualityThreshold: 0.9,
testGenerationMode: "unit"
},
preprocessor: (args, options) => ({
task: `Refactor ${args[0] || "codebase"}`,
context: {
target: args[0] || process.cwd(),
scope: options.scope || "moderate",
preserveApi: options.preserveApi !== false
}
})
});
mappings.set("publish", {
skillName: "publish",
primaryAgent: "publish",
secondaryAgents: ["testing", "linting"],
taskTemplate: "Prepare and execute {publishType} release. Run tests, update versions, generate changelog, publish.",
defaultOptions: {
maxParallel: 1,
reviewStages: 1,
testGenerationMode: "all"
},
preprocessor: (args, options) => ({
task: `Publish ${options.type || "npm"} release`,
context: {
version: args[0],
publishType: options.type || "npm",
prerelease: options.prerelease || false,
skipTests: options.skipTests || false
}
})
});
return mappings;
}
/**
* Execute any skill through RLM orchestration first
*/
async executeSkill(skillName, args, options) {
logger.info(`Executing skill through RLM: ${skillName}`, { args, options });
const mapping = this.skillMappings.get(skillName);
if (mapping) {
return this.executeViaRLM(mapping, args, options || {});
}
if (skillName === "rlm") {
const task = args.join(" ") || "Analyze and optimize current code";
const result = await this.rlmOrchestrator.execute(
task,
options || {},
options
);
return {
success: result.success,
message: `RLM execution ${result.success ? "completed" : "failed"}`,
data: result
};
}
logger.warn(`Skill ${skillName} not mapped to RLM, using legacy execution`);
return this.skillsManager.executeSkill(skillName, args, options);
}
/**
* Execute skill via RLM orchestration
*/
async executeViaRLM(mapping, args, options) {
try {
const { task, context } = mapping.preprocessor ? mapping.preprocessor(args, options) : {
task: mapping.taskTemplate.replace("{args}", args.join(" ")),
context: { args, ...options }
};
const rlmOptions = {
...mapping.defaultOptions,
...options,
// Force specific agents if specified
agents: [mapping.primaryAgent, ...mapping.secondaryAgents || []]
};
const result = await this.rlmOrchestrator.execute(
task,
context,
rlmOptions
);
if (mapping.postprocessor) {
return mapping.postprocessor(result);
}
return {
success: result.success,
message: `${mapping.skillName} ${result.success ? "completed" : "failed"}`,
data: {
duration: result.duration,
tokens: result.totalTokens,
cost: result.totalCost,
improvements: result.improvements,
testsGenerated: result.testsGenerated,
issuesFound: result.issuesFound,
issuesFixed: result.issuesFixed,
details: result.rootNode
}
};
} catch (error) {
logger.error(`RLM execution failed for ${mapping.skillName}:`, error);
return {
success: false,
message: `Failed to execute ${mapping.skillName}: ${error.message}`
};
}
}
/**
* Helper: Find node by agent type in task tree
*/
findNodeByAgent(node, agentType) {
if (node.agent === agentType) {
return node;
}
if (node.children) {
for (const child of node.children) {
const found = this.findNodeByAgent(child, agentType);
if (found) return found;
}
}
return null;
}
/**
* Get available skills (all RLM-mapped + legacy)
*/
getAvailableSkills() {
const rlmSkills = Array.from(this.skillMappings.keys());
const legacySkills = this.skillsManager.getAvailableSkills();
const allSkills = /* @__PURE__ */ new Set([...rlmSkills, ...legacySkills, "rlm"]);
return Array.from(allSkills);
}
/**
* Get skill help
*/
getSkillHelp(skillName) {
const mapping = this.skillMappings.get(skillName);
if (mapping) {
return `
${skillName} (RLM-Orchestrated)
Primary Agent: ${mapping.primaryAgent}
Secondary Agents: ${mapping.secondaryAgents?.join(", ") || "none"}
${mapping.taskTemplate}
This skill is executed through RLM orchestration for:
- Automatic task decomposition
- Parallel agent execution
- Multi-stage quality review
- Comprehensive result aggregation
`;
}
return this.skillsManager.getSkillHelp(skillName);
}
/**
* Execute task with intelligent routing
*/
async executeTask(task, context) {
const taskAnalysis = this.analyzeTask(task);
if (taskAnalysis.suggestedSkill) {
return this.executeSkill(
taskAnalysis.suggestedSkill,
taskAnalysis.args,
taskAnalysis.options
);
}
const result = await this.rlmOrchestrator.execute(task, context || {}, {
maxParallel: 5,
reviewStages: 2,
qualityThreshold: 0.85,
verboseLogging: true
});
return {
success: result.success,
message: `Task ${result.success ? "completed" : "failed"}`,
data: result
};
}
/**
* Analyze task to determine best routing
*/
analyzeTask(task) {
const taskLower = task.toLowerCase();
const patterns = [
{ pattern: /lint|format|style|quality/i, skill: "lint" },
{ pattern: /test|coverage|unit|integration/i, skill: "test" },
{ pattern: /review|analyze|improve/i, skill: "review" },
{ pattern: /refactor|restructure|clean/i, skill: "refactor" },
{ pattern: /handoff|transfer|pass/i, skill: "handoff" },
{ pattern: /checkpoint|backup|save/i, skill: "checkpoint" },
{ pattern: /search|find|dig|history/i, skill: "dig" },
{ pattern: /publish|release|deploy/i, skill: "publish" }
];
for (const { pattern, skill } of patterns) {
if (pattern.test(taskLower)) {
return {
suggestedSkill: skill,
args: [task],
options: {}
};
}
}
return {
args: [task],
options: {}
};
}
}
let unifiedOrchestrator = null;
function initializeUnifiedOrchestrator(frameManager, dualStackManager, contextRetriever, taskStore, skillContext) {
if (!unifiedOrchestrator) {
unifiedOrchestrator = new UnifiedRLMOrchestrator(
frameManager,
dualStackManager,
contextRetriever,
taskStore,
skillContext
);
}
return unifiedOrchestrator;
}
function getUnifiedOrchestrator() {
return unifiedOrchestrator;
}
export {
UnifiedRLMOrchestrator,
getUnifiedOrchestrator,
initializeUnifiedOrchestrator
};
//# sourceMappingURL=unified-rlm-orchestrator.js.map