@stackmemoryai/stackmemory 0.5.64 → 0.5.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +69 -346
  2. package/bin/claude-sm +1 -1
  3. package/bin/claude-smd +1 -1
  4. package/bin/codex-sm +6 -0
  5. package/bin/codex-smd +1 -1
  6. package/bin/opencode-sm +1 -1
  7. package/dist/src/cli/claude-sm.js +162 -25
  8. package/dist/src/cli/claude-sm.js.map +2 -2
  9. package/dist/src/cli/commands/ping.js +14 -0
  10. package/dist/src/cli/commands/ping.js.map +7 -0
  11. package/dist/src/cli/commands/ralph.js +103 -1
  12. package/dist/src/cli/commands/ralph.js.map +2 -2
  13. package/dist/src/cli/commands/retrieval.js +1 -1
  14. package/dist/src/cli/commands/retrieval.js.map +2 -2
  15. package/dist/src/cli/commands/skills.js +300 -1
  16. package/dist/src/cli/commands/skills.js.map +2 -2
  17. package/dist/src/cli/index.js +362 -20
  18. package/dist/src/cli/index.js.map +2 -2
  19. package/dist/src/core/digest/types.js +1 -1
  20. package/dist/src/core/digest/types.js.map +1 -1
  21. package/dist/src/core/extensions/provider-adapter.js +2 -5
  22. package/dist/src/core/extensions/provider-adapter.js.map +2 -2
  23. package/dist/src/core/retrieval/llm-provider.js +2 -2
  24. package/dist/src/core/retrieval/llm-provider.js.map +1 -1
  25. package/dist/src/core/retrieval/types.js +1 -1
  26. package/dist/src/core/retrieval/types.js.map +1 -1
  27. package/dist/src/features/sweep/pty-wrapper.js +15 -5
  28. package/dist/src/features/sweep/pty-wrapper.js.map +2 -2
  29. package/dist/src/features/workers/tmux-manager.js +71 -0
  30. package/dist/src/features/workers/tmux-manager.js.map +7 -0
  31. package/dist/src/features/workers/worker-registry.js +52 -0
  32. package/dist/src/features/workers/worker-registry.js.map +7 -0
  33. package/dist/src/integrations/linear/webhook-handler.js +82 -0
  34. package/dist/src/integrations/linear/webhook-handler.js.map +2 -2
  35. package/dist/src/integrations/mcp/pending-utils.js +33 -0
  36. package/dist/src/integrations/mcp/pending-utils.js.map +7 -0
  37. package/dist/src/integrations/mcp/server.js +571 -1
  38. package/dist/src/integrations/mcp/server.js.map +2 -2
  39. package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +2 -2
  40. package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js.map +2 -2
  41. package/dist/src/orchestrators/multimodal/constants.js +17 -0
  42. package/dist/src/orchestrators/multimodal/constants.js.map +7 -0
  43. package/dist/src/orchestrators/multimodal/harness.js +292 -0
  44. package/dist/src/orchestrators/multimodal/harness.js.map +7 -0
  45. package/dist/src/orchestrators/multimodal/providers.js +98 -0
  46. package/dist/src/orchestrators/multimodal/providers.js.map +7 -0
  47. package/dist/src/orchestrators/multimodal/types.js +5 -0
  48. package/dist/src/orchestrators/multimodal/types.js.map +7 -0
  49. package/dist/src/orchestrators/multimodal/utils.js +25 -0
  50. package/dist/src/orchestrators/multimodal/utils.js.map +7 -0
  51. package/dist/src/skills/claude-skills.js +116 -1
  52. package/dist/src/skills/claude-skills.js.map +2 -2
  53. package/dist/src/skills/linear-task-runner.js +262 -0
  54. package/dist/src/skills/linear-task-runner.js.map +7 -0
  55. package/dist/src/skills/recursive-agent-orchestrator.js +114 -85
  56. package/dist/src/skills/recursive-agent-orchestrator.js.map +2 -2
  57. package/dist/src/skills/spec-generator-skill.js +441 -0
  58. package/dist/src/skills/spec-generator-skill.js.map +7 -0
  59. package/package.json +14 -9
  60. package/scripts/claude-code-wrapper.sh +18 -30
  61. package/scripts/demos/ralph-integration-demo.ts +14 -13
  62. package/scripts/demos/trace-demo.ts +7 -21
  63. package/scripts/demos/trace-test.ts +20 -8
  64. package/scripts/install-claude-hooks.sh +2 -2
  65. package/scripts/verify-dist.cjs +83 -0
  66. package/templates/claude-hooks/post-edit-sweep.js +7 -10
@@ -336,7 +336,7 @@ const defaultModelConfigs = {
336
336
  {
337
337
  tier: "worker",
338
338
  provider: "claude",
339
- model: "claude-3-haiku-20240307",
339
+ model: "claude-3-5-haiku-20241022",
340
340
  costPerToken: 25e-5,
341
341
  // $0.25/1M input tokens
342
342
  capabilities: [
@@ -352,7 +352,7 @@ const defaultModelConfigs = {
352
352
  provider: "openai",
353
353
  model: "gpt-4o-mini",
354
354
  costPerToken: 15e-5,
355
- // $0.15/1M input tokens
355
+ // $0.15/1M input tokens
356
356
  capabilities: [
357
357
  "rapid_prototyping",
358
358
  "script_writing",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/integrations/ralph/patterns/oracle-worker-pattern.ts"],
4
- "sourcesContent": ["/**\n * Oracle/Worker Pattern Implementation for StackMemory Swarms\n * \n * Uses high-end model (Oracle) for planning, review, and coordination\n * Uses smaller models (Workers) for task execution and implementation\n * \n * Cost-effective scaling: Intelligence where needed, efficiency for execution\n */\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../../../core/monitoring/logger.js';\nimport { SwarmCoordinator } from '../swarm/swarm-coordinator.js';\nimport { RalphStackMemoryBridge } from '../bridge/ralph-stackmemory-bridge.js';\n\n// Model tiers based on capability and cost\nexport type ModelTier = 'oracle' | 'worker' | 'reviewer';\n\nexport interface ModelConfig {\n tier: ModelTier;\n provider: 'claude' | 'openai' | 'anthropic';\n model: string;\n costPerToken: number;\n capabilities: string[];\n}\n\nexport interface OracleWorkerConfig {\n oracle: ModelConfig;\n workers: ModelConfig[];\n reviewers: ModelConfig[];\n maxWorkers: number;\n coordinationInterval: number;\n costBudget?: number;\n}\n\nexport interface TaskDecomposition {\n id: string;\n type: 'planning' | 'implementation' | 'review' | 'coordination';\n priority: number;\n complexity: 'low' | 'medium' | 'high';\n estimatedTokens: number;\n assignedModel: ModelTier;\n dependencies: string[];\n acceptanceCriteria: string[];\n}\n\n/**\n * Oracle/Worker Pattern Coordinator\n * Implements cost-effective multi-model orchestration\n */\nexport class OracleWorkerCoordinator extends SwarmCoordinator {\n private oracle: ModelConfig;\n private workerPool: ModelConfig[];\n private reviewerPool: ModelConfig[];\n private costTracker: {\n oracleSpent: number;\n workerSpent: number;\n reviewerSpent: number;\n totalBudget: number;\n };\n \n constructor(config: OracleWorkerConfig) {\n super({\n maxAgents: config.maxWorkers + 2, // Workers + Oracle + Reviewer\n coordinationInterval: config.coordinationInterval,\n enableDynamicPlanning: true,\n pathologicalBehaviorDetection: true,\n });\n\n this.oracle = config.oracle;\n this.workerPool = config.workers;\n this.reviewerPool = config.reviewers;\n \n this.costTracker = {\n oracleSpent: 0,\n workerSpent: 0,\n reviewerSpent: 0,\n totalBudget: config.costBudget || 10.0, // $10 default\n };\n\n logger.info('Oracle/Worker coordinator initialized', {\n oracle: this.oracle.model,\n workers: this.workerPool.length,\n budget: this.costTracker.totalBudget,\n });\n }\n\n /**\n * Launch swarm with Oracle/Worker pattern\n */\n async launchOracleWorkerSwarm(\n projectDescription: string,\n taskHints?: string[]\n ): Promise<string> {\n logger.info('Launching Oracle/Worker swarm', {\n project: projectDescription.substring(0, 100),\n });\n\n // Phase 1: Oracle Planning\n const oracleTaskId = await this.createOracleTask(\n 'project_planning',\n projectDescription,\n taskHints\n );\n \n const decomposition = await this.executeOracleTask(oracleTaskId);\n \n // Phase 2: Worker Assignment\n const workerTasks = this.allocateTasksToWorkers(decomposition);\n \n // Phase 3: Parallel Worker Execution\n const workerPromises = workerTasks.map(task => \n this.executeWorkerTask(task)\n );\n \n // Phase 4: Oracle Review & Coordination\n const reviewTaskId = await this.scheduleOracleReview(decomposition);\n \n // Execute workers in parallel, oracle coordinates\n const [workerResults, reviewResult] = await Promise.all([\n Promise.allSettled(workerPromises),\n this.executeOracleTask(reviewTaskId)\n ]);\n\n // Phase 5: Final Integration\n const swarmId = await this.integrateResults(workerResults, reviewResult);\n \n this.logCostAnalysis();\n return swarmId;\n }\n\n /**\n * Create planning task for Oracle\n */\n private async createOracleTask(\n type: string,\n description: string,\n hints?: string[]\n ): Promise<string> {\n const taskId = uuidv4();\n \n const oraclePrompt = this.buildOraclePrompt(type, description, hints);\n const estimatedTokens = this.estimateTokens(oraclePrompt);\n \n logger.info('Oracle task created', {\n taskId,\n type,\n estimatedTokens,\n estimatedCost: estimatedTokens * this.oracle.costPerToken,\n });\n\n return taskId;\n }\n\n /**\n * Build specialized prompt for Oracle model\n */\n private buildOraclePrompt(\n type: string,\n description: string,\n hints?: string[]\n ): string {\n const basePrompt = `\n# ORACLE ROLE: Strategic Planning & Coordination\n\nYou are the Oracle in an Oracle/Worker pattern. Your role:\n- HIGH-LEVEL STRATEGIC thinking\n- TASK DECOMPOSITION for worker agents \n- QUALITY CONTROL and review\n- COORDINATION between workers\n- ERROR CORRECTION and replanning\n\n## Project Context\n${description}\n\n${hints ? `## Hints & Context\\n${hints.map(h => `- ${h}`).join('\\n')}` : ''}\n\n## Your Oracle Responsibilities\n1. **Decompose** this project into discrete, parallelizable tasks\n2. **Assign complexity levels** (low/medium/high) to guide worker selection\n3. **Define acceptance criteria** for each task\n4. **Identify dependencies** between tasks\n5. **Plan coordination touchpoints** for integration\n\n## Worker Constraints\n- Workers are smaller models optimized for focused execution\n- Workers excel at: implementation, testing, documentation, simple analysis\n- Workers struggle with: complex architecture, strategic decisions, cross-cutting concerns\n\n## Output Required\nProvide a detailed task decomposition in JSON format:\n\n\\`\\`\\`json\n{\n \"project_summary\": \"Brief overview\",\n \"task_decomposition\": [\n {\n \"id\": \"unique-id\",\n \"title\": \"Task name\",\n \"description\": \"Detailed description\",\n \"complexity\": \"low|medium|high\",\n \"type\": \"implementation|testing|documentation|analysis\",\n \"estimated_effort\": \"1-5 scale\",\n \"worker_requirements\": [\"specific capabilities needed\"],\n \"acceptance_criteria\": [\"criterion 1\", \"criterion 2\"],\n \"dependencies\": [\"task-id-1\", \"task-id-2\"]\n }\n ],\n \"coordination_plan\": {\n \"integration_points\": [\"When to sync between workers\"],\n \"review_checkpoints\": [\"When Oracle should review progress\"],\n \"risk_mitigation\": [\"Potential issues and solutions\"]\n }\n}\n\\`\\`\\`\n\nRemember: Your intelligence is expensive. Focus on high-value strategic thinking that workers cannot do effectively.\n `;\n\n return basePrompt;\n }\n\n /**\n * Execute Oracle task with high-end model\n */\n private async executeOracleTask(taskId: string): Promise<TaskDecomposition[]> {\n logger.info('Executing Oracle task', { taskId });\n \n // Create Ralph loop with Oracle model configuration\n const ralph = new RalphStackMemoryBridge({\n baseDir: `.oracle/${taskId}`,\n maxIterations: 3, // Oracle should be efficient\n useStackMemory: true,\n });\n\n // Execute with Oracle model (implementation would integrate with actual model APIs)\n const result = await ralph.run();\n \n // Track Oracle costs\n const tokens = this.estimateTokens(result);\n const cost = tokens * this.oracle.costPerToken;\n this.costTracker.oracleSpent += cost;\n \n logger.info('Oracle task completed', {\n taskId,\n tokensUsed: tokens,\n cost: cost.toFixed(4),\n });\n\n return this.parseTaskDecomposition(result);\n }\n\n /**\n * Allocate decomposed tasks to worker models\n */\n private allocateTasksToWorkers(\n decomposition: TaskDecomposition[]\n ): TaskDecomposition[] {\n const allocatedTasks: TaskDecomposition[] = [];\n\n for (const task of decomposition) {\n // Select optimal worker model based on task complexity\n const workerModel = this.selectWorkerForTask(task);\n \n // Create worker-specific prompt\n const workerPrompt = this.buildWorkerPrompt(task, workerModel);\n \n allocatedTasks.push({\n ...task,\n assignedModel: 'worker' as ModelTier,\n });\n\n logger.debug('Task allocated to worker', {\n taskId: task.id,\n complexity: task.complexity,\n worker: workerModel.model,\n });\n }\n\n return allocatedTasks;\n }\n\n /**\n * Select optimal worker model for task complexity\n */\n private selectWorkerForTask(task: TaskDecomposition): ModelConfig {\n // Simple allocation strategy - can be enhanced\n if (task.complexity === 'high') {\n // Use best available worker for complex tasks\n return this.workerPool[0];\n } else {\n // Use cheapest worker for simple tasks\n return this.workerPool.reduce((cheapest, current) => \n current.costPerToken < cheapest.costPerToken ? current : cheapest\n );\n }\n }\n\n /**\n * Build focused prompt for worker models\n */\n private buildWorkerPrompt(\n task: TaskDecomposition,\n worker: ModelConfig\n ): string {\n return `\n# WORKER ROLE: Focused Task Execution\n\nYou are a specialized worker in an Oracle/Worker pattern.\n\n## Your Task\n${task.type}: ${task.title}\n\n${task.description}\n\n## Success Criteria\n${task.acceptanceCriteria.map(c => `- ${c}`).join('\\n')}\n\n## Worker Guidelines\n- FOCUS on this specific task only\n- IMPLEMENT according to the specifications provided\n- ASK for clarification if requirements are unclear\n- COMMUNICATE progress through shared context\n- COMPLETE the task efficiently without over-engineering\n\n## Constraints\n- You are optimized for execution, not planning\n- Stay within your assigned scope\n- Collaborate with other workers through shared context\n- The Oracle will handle integration and review\n\nExecute your task now.\n `;\n }\n\n /**\n * Execute worker task with cost tracking\n */\n private async executeWorkerTask(task: TaskDecomposition): Promise<any> {\n logger.info('Executing worker task', { \n taskId: task.id,\n complexity: task.complexity \n });\n\n const ralph = new RalphStackMemoryBridge({\n baseDir: `.workers/${task.id}`,\n maxIterations: task.complexity === 'low' ? 3 : 7,\n useStackMemory: true,\n });\n\n const result = await ralph.run();\n \n // Track worker costs\n const workerModel = this.selectWorkerForTask(task);\n const tokens = this.estimateTokens(result);\n const cost = tokens * workerModel.costPerToken;\n this.costTracker.workerSpent += cost;\n\n logger.info('Worker task completed', {\n taskId: task.id,\n tokensUsed: tokens,\n cost: cost.toFixed(4),\n });\n\n return result;\n }\n\n /**\n * Schedule Oracle review of worker progress\n */\n private async scheduleOracleReview(\n decomposition: TaskDecomposition[]\n ): Promise<string> {\n const reviewTaskId = uuidv4();\n \n // Oracle reviews worker outputs and coordinates integration\n logger.info('Oracle review scheduled', { \n reviewTaskId,\n tasksToReview: decomposition.length \n });\n\n return reviewTaskId;\n }\n\n /**\n * Integrate worker results under Oracle coordination\n */\n private async integrateResults(\n workerResults: PromiseSettledResult<any>[],\n reviewResult: any\n ): Promise<string> {\n const swarmId = uuidv4();\n \n const successfulTasks = workerResults.filter(\n result => result.status === 'fulfilled'\n ).length;\n\n logger.info('Integration completed', {\n swarmId,\n totalTasks: workerResults.length,\n successfulTasks,\n successRate: (successfulTasks / workerResults.length * 100).toFixed(1),\n });\n\n return swarmId;\n }\n\n /**\n * Parse task decomposition from Oracle output\n */\n private parseTaskDecomposition(output: string): TaskDecomposition[] {\n // Parse JSON from Oracle output\n // Implementation would extract the JSON task decomposition\n return [];\n }\n\n /**\n * Estimate token usage for cost calculation\n */\n private estimateTokens(text: string): number {\n // Rough estimation: ~4 characters per token\n return Math.ceil(text.length / 4);\n }\n\n /**\n * Log cost analysis and efficiency metrics\n */\n private logCostAnalysis(): void {\n const total = this.costTracker.oracleSpent + \n this.costTracker.workerSpent + \n this.costTracker.reviewerSpent;\n\n const savings = this.calculateTraditionalCost() - total;\n\n logger.info('Oracle/Worker Cost Analysis', {\n oracleSpent: `$${this.costTracker.oracleSpent.toFixed(4)}`,\n workerSpent: `$${this.costTracker.workerSpent.toFixed(4)}`,\n totalSpent: `$${total.toFixed(4)}`,\n budgetUsed: `${(total / this.costTracker.totalBudget * 100).toFixed(1)}%`,\n estimatedSavings: `$${savings.toFixed(4)}`,\n efficiency: `${(this.costTracker.workerSpent / total * 100).toFixed(1)}% worker tasks`,\n });\n }\n\n /**\n * Calculate what this would cost with all-Oracle approach\n */\n private calculateTraditionalCost(): number {\n const totalSpent = this.costTracker.oracleSpent + \n this.costTracker.workerSpent + \n this.costTracker.reviewerSpent;\n \n // Estimate if everything was done with Oracle model\n const avgWorkerCost = this.workerPool[0]?.costPerToken || 0.001;\n const workerTokensAsOracle = this.costTracker.workerSpent / avgWorkerCost;\n \n return this.costTracker.oracleSpent + \n (workerTokensAsOracle * this.oracle.costPerToken);\n }\n}\n\n/**\n * Default model configurations for Oracle/Worker pattern\n */\nexport const defaultModelConfigs: Record<ModelTier, ModelConfig[]> = {\n oracle: [\n {\n tier: 'oracle',\n provider: 'claude',\n model: 'claude-3-opus-20240229',\n costPerToken: 0.015, // $15/1M input tokens\n capabilities: [\n 'strategic_planning',\n 'complex_reasoning',\n 'task_decomposition',\n 'quality_review',\n 'error_correction'\n ]\n }\n ],\n \n worker: [\n {\n tier: 'worker',\n provider: 'claude', \n model: 'claude-3-haiku-20240307',\n costPerToken: 0.00025, // $0.25/1M input tokens\n capabilities: [\n 'code_implementation',\n 'unit_testing',\n 'documentation',\n 'simple_analysis',\n 'data_processing'\n ]\n },\n {\n tier: 'worker',\n provider: 'openai',\n model: 'gpt-4o-mini',\n costPerToken: 0.00015, // $0.15/1M input tokens \n capabilities: [\n 'rapid_prototyping',\n 'script_writing',\n 'basic_testing',\n 'formatting',\n 'simple_refactoring'\n ]\n }\n ],\n\n reviewer: [\n {\n tier: 'reviewer',\n provider: 'claude',\n model: 'claude-3-sonnet-20240229', \n costPerToken: 0.003, // $3/1M input tokens\n capabilities: [\n 'code_review',\n 'quality_assessment',\n 'integration_testing',\n 'performance_analysis',\n 'security_review'\n ]\n }\n ]\n};\n\nexport default OracleWorkerCoordinator;"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Oracle/Worker Pattern Implementation for StackMemory Swarms\n *\n * Uses high-end model (Oracle) for planning, review, and coordination\n * Uses smaller models (Workers) for task execution and implementation\n *\n * Cost-effective scaling: Intelligence where needed, efficiency for execution\n */\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../../../core/monitoring/logger.js';\nimport { SwarmCoordinator } from '../swarm/swarm-coordinator.js';\nimport { RalphStackMemoryBridge } from '../bridge/ralph-stackmemory-bridge.js';\n\n// Model tiers based on capability and cost\nexport type ModelTier = 'oracle' | 'worker' | 'reviewer';\n\nexport interface ModelConfig {\n tier: ModelTier;\n provider: 'claude' | 'openai' | 'anthropic';\n model: string;\n costPerToken: number;\n capabilities: string[];\n}\n\nexport interface OracleWorkerConfig {\n oracle: ModelConfig;\n workers: ModelConfig[];\n reviewers: ModelConfig[];\n maxWorkers: number;\n coordinationInterval: number;\n costBudget?: number;\n}\n\nexport interface TaskDecomposition {\n id: string;\n type: 'planning' | 'implementation' | 'review' | 'coordination';\n priority: number;\n complexity: 'low' | 'medium' | 'high';\n estimatedTokens: number;\n assignedModel: ModelTier;\n dependencies: string[];\n acceptanceCriteria: string[];\n}\n\n/**\n * Oracle/Worker Pattern Coordinator\n * Implements cost-effective multi-model orchestration\n */\nexport class OracleWorkerCoordinator extends SwarmCoordinator {\n private oracle: ModelConfig;\n private workerPool: ModelConfig[];\n private reviewerPool: ModelConfig[];\n private costTracker: {\n oracleSpent: number;\n workerSpent: number;\n reviewerSpent: number;\n totalBudget: number;\n };\n\n constructor(config: OracleWorkerConfig) {\n super({\n maxAgents: config.maxWorkers + 2, // Workers + Oracle + Reviewer\n coordinationInterval: config.coordinationInterval,\n enableDynamicPlanning: true,\n pathologicalBehaviorDetection: true,\n });\n\n this.oracle = config.oracle;\n this.workerPool = config.workers;\n this.reviewerPool = config.reviewers;\n\n this.costTracker = {\n oracleSpent: 0,\n workerSpent: 0,\n reviewerSpent: 0,\n totalBudget: config.costBudget || 10.0, // $10 default\n };\n\n logger.info('Oracle/Worker coordinator initialized', {\n oracle: this.oracle.model,\n workers: this.workerPool.length,\n budget: this.costTracker.totalBudget,\n });\n }\n\n /**\n * Launch swarm with Oracle/Worker pattern\n */\n async launchOracleWorkerSwarm(\n projectDescription: string,\n taskHints?: string[]\n ): Promise<string> {\n logger.info('Launching Oracle/Worker swarm', {\n project: projectDescription.substring(0, 100),\n });\n\n // Phase 1: Oracle Planning\n const oracleTaskId = await this.createOracleTask(\n 'project_planning',\n projectDescription,\n taskHints\n );\n\n const decomposition = await this.executeOracleTask(oracleTaskId);\n\n // Phase 2: Worker Assignment\n const workerTasks = this.allocateTasksToWorkers(decomposition);\n\n // Phase 3: Parallel Worker Execution\n const workerPromises = workerTasks.map((task) =>\n this.executeWorkerTask(task)\n );\n\n // Phase 4: Oracle Review & Coordination\n const reviewTaskId = await this.scheduleOracleReview(decomposition);\n\n // Execute workers in parallel, oracle coordinates\n const [workerResults, reviewResult] = await Promise.all([\n Promise.allSettled(workerPromises),\n this.executeOracleTask(reviewTaskId),\n ]);\n\n // Phase 5: Final Integration\n const swarmId = await this.integrateResults(workerResults, reviewResult);\n\n this.logCostAnalysis();\n return swarmId;\n }\n\n /**\n * Create planning task for Oracle\n */\n private async createOracleTask(\n type: string,\n description: string,\n hints?: string[]\n ): Promise<string> {\n const taskId = uuidv4();\n\n const oraclePrompt = this.buildOraclePrompt(type, description, hints);\n const estimatedTokens = this.estimateTokens(oraclePrompt);\n\n logger.info('Oracle task created', {\n taskId,\n type,\n estimatedTokens,\n estimatedCost: estimatedTokens * this.oracle.costPerToken,\n });\n\n return taskId;\n }\n\n /**\n * Build specialized prompt for Oracle model\n */\n private buildOraclePrompt(\n type: string,\n description: string,\n hints?: string[]\n ): string {\n const basePrompt = `\n# ORACLE ROLE: Strategic Planning & Coordination\n\nYou are the Oracle in an Oracle/Worker pattern. Your role:\n- HIGH-LEVEL STRATEGIC thinking\n- TASK DECOMPOSITION for worker agents \n- QUALITY CONTROL and review\n- COORDINATION between workers\n- ERROR CORRECTION and replanning\n\n## Project Context\n${description}\n\n${hints ? `## Hints & Context\\n${hints.map((h) => `- ${h}`).join('\\n')}` : ''}\n\n## Your Oracle Responsibilities\n1. **Decompose** this project into discrete, parallelizable tasks\n2. **Assign complexity levels** (low/medium/high) to guide worker selection\n3. **Define acceptance criteria** for each task\n4. **Identify dependencies** between tasks\n5. **Plan coordination touchpoints** for integration\n\n## Worker Constraints\n- Workers are smaller models optimized for focused execution\n- Workers excel at: implementation, testing, documentation, simple analysis\n- Workers struggle with: complex architecture, strategic decisions, cross-cutting concerns\n\n## Output Required\nProvide a detailed task decomposition in JSON format:\n\n\\`\\`\\`json\n{\n \"project_summary\": \"Brief overview\",\n \"task_decomposition\": [\n {\n \"id\": \"unique-id\",\n \"title\": \"Task name\",\n \"description\": \"Detailed description\",\n \"complexity\": \"low|medium|high\",\n \"type\": \"implementation|testing|documentation|analysis\",\n \"estimated_effort\": \"1-5 scale\",\n \"worker_requirements\": [\"specific capabilities needed\"],\n \"acceptance_criteria\": [\"criterion 1\", \"criterion 2\"],\n \"dependencies\": [\"task-id-1\", \"task-id-2\"]\n }\n ],\n \"coordination_plan\": {\n \"integration_points\": [\"When to sync between workers\"],\n \"review_checkpoints\": [\"When Oracle should review progress\"],\n \"risk_mitigation\": [\"Potential issues and solutions\"]\n }\n}\n\\`\\`\\`\n\nRemember: Your intelligence is expensive. Focus on high-value strategic thinking that workers cannot do effectively.\n `;\n\n return basePrompt;\n }\n\n /**\n * Execute Oracle task with high-end model\n */\n private async executeOracleTask(\n taskId: string\n ): Promise<TaskDecomposition[]> {\n logger.info('Executing Oracle task', { taskId });\n\n // Create Ralph loop with Oracle model configuration\n const ralph = new RalphStackMemoryBridge({\n baseDir: `.oracle/${taskId}`,\n maxIterations: 3, // Oracle should be efficient\n useStackMemory: true,\n });\n\n // Execute with Oracle model (implementation would integrate with actual model APIs)\n const result = await ralph.run();\n\n // Track Oracle costs\n const tokens = this.estimateTokens(result);\n const cost = tokens * this.oracle.costPerToken;\n this.costTracker.oracleSpent += cost;\n\n logger.info('Oracle task completed', {\n taskId,\n tokensUsed: tokens,\n cost: cost.toFixed(4),\n });\n\n return this.parseTaskDecomposition(result);\n }\n\n /**\n * Allocate decomposed tasks to worker models\n */\n private allocateTasksToWorkers(\n decomposition: TaskDecomposition[]\n ): TaskDecomposition[] {\n const allocatedTasks: TaskDecomposition[] = [];\n\n for (const task of decomposition) {\n // Select optimal worker model based on task complexity\n const workerModel = this.selectWorkerForTask(task);\n\n // Create worker-specific prompt\n const workerPrompt = this.buildWorkerPrompt(task, workerModel);\n\n allocatedTasks.push({\n ...task,\n assignedModel: 'worker' as ModelTier,\n });\n\n logger.debug('Task allocated to worker', {\n taskId: task.id,\n complexity: task.complexity,\n worker: workerModel.model,\n });\n }\n\n return allocatedTasks;\n }\n\n /**\n * Select optimal worker model for task complexity\n */\n private selectWorkerForTask(task: TaskDecomposition): ModelConfig {\n // Simple allocation strategy - can be enhanced\n if (task.complexity === 'high') {\n // Use best available worker for complex tasks\n return this.workerPool[0];\n } else {\n // Use cheapest worker for simple tasks\n return this.workerPool.reduce((cheapest, current) =>\n current.costPerToken < cheapest.costPerToken ? current : cheapest\n );\n }\n }\n\n /**\n * Build focused prompt for worker models\n */\n private buildWorkerPrompt(\n task: TaskDecomposition,\n worker: ModelConfig\n ): string {\n return `\n# WORKER ROLE: Focused Task Execution\n\nYou are a specialized worker in an Oracle/Worker pattern.\n\n## Your Task\n${task.type}: ${task.title}\n\n${task.description}\n\n## Success Criteria\n${task.acceptanceCriteria.map((c) => `- ${c}`).join('\\n')}\n\n## Worker Guidelines\n- FOCUS on this specific task only\n- IMPLEMENT according to the specifications provided\n- ASK for clarification if requirements are unclear\n- COMMUNICATE progress through shared context\n- COMPLETE the task efficiently without over-engineering\n\n## Constraints\n- You are optimized for execution, not planning\n- Stay within your assigned scope\n- Collaborate with other workers through shared context\n- The Oracle will handle integration and review\n\nExecute your task now.\n `;\n }\n\n /**\n * Execute worker task with cost tracking\n */\n private async executeWorkerTask(task: TaskDecomposition): Promise<any> {\n logger.info('Executing worker task', {\n taskId: task.id,\n complexity: task.complexity,\n });\n\n const ralph = new RalphStackMemoryBridge({\n baseDir: `.workers/${task.id}`,\n maxIterations: task.complexity === 'low' ? 3 : 7,\n useStackMemory: true,\n });\n\n const result = await ralph.run();\n\n // Track worker costs\n const workerModel = this.selectWorkerForTask(task);\n const tokens = this.estimateTokens(result);\n const cost = tokens * workerModel.costPerToken;\n this.costTracker.workerSpent += cost;\n\n logger.info('Worker task completed', {\n taskId: task.id,\n tokensUsed: tokens,\n cost: cost.toFixed(4),\n });\n\n return result;\n }\n\n /**\n * Schedule Oracle review of worker progress\n */\n private async scheduleOracleReview(\n decomposition: TaskDecomposition[]\n ): Promise<string> {\n const reviewTaskId = uuidv4();\n\n // Oracle reviews worker outputs and coordinates integration\n logger.info('Oracle review scheduled', {\n reviewTaskId,\n tasksToReview: decomposition.length,\n });\n\n return reviewTaskId;\n }\n\n /**\n * Integrate worker results under Oracle coordination\n */\n private async integrateResults(\n workerResults: PromiseSettledResult<any>[],\n reviewResult: any\n ): Promise<string> {\n const swarmId = uuidv4();\n\n const successfulTasks = workerResults.filter(\n (result) => result.status === 'fulfilled'\n ).length;\n\n logger.info('Integration completed', {\n swarmId,\n totalTasks: workerResults.length,\n successfulTasks,\n successRate: ((successfulTasks / workerResults.length) * 100).toFixed(1),\n });\n\n return swarmId;\n }\n\n /**\n * Parse task decomposition from Oracle output\n */\n private parseTaskDecomposition(output: string): TaskDecomposition[] {\n // Parse JSON from Oracle output\n // Implementation would extract the JSON task decomposition\n return [];\n }\n\n /**\n * Estimate token usage for cost calculation\n */\n private estimateTokens(text: string): number {\n // Rough estimation: ~4 characters per token\n return Math.ceil(text.length / 4);\n }\n\n /**\n * Log cost analysis and efficiency metrics\n */\n private logCostAnalysis(): void {\n const total =\n this.costTracker.oracleSpent +\n this.costTracker.workerSpent +\n this.costTracker.reviewerSpent;\n\n const savings = this.calculateTraditionalCost() - total;\n\n logger.info('Oracle/Worker Cost Analysis', {\n oracleSpent: `$${this.costTracker.oracleSpent.toFixed(4)}`,\n workerSpent: `$${this.costTracker.workerSpent.toFixed(4)}`,\n totalSpent: `$${total.toFixed(4)}`,\n budgetUsed: `${((total / this.costTracker.totalBudget) * 100).toFixed(1)}%`,\n estimatedSavings: `$${savings.toFixed(4)}`,\n efficiency: `${((this.costTracker.workerSpent / total) * 100).toFixed(1)}% worker tasks`,\n });\n }\n\n /**\n * Calculate what this would cost with all-Oracle approach\n */\n private calculateTraditionalCost(): number {\n const totalSpent =\n this.costTracker.oracleSpent +\n this.costTracker.workerSpent +\n this.costTracker.reviewerSpent;\n\n // Estimate if everything was done with Oracle model\n const avgWorkerCost = this.workerPool[0]?.costPerToken || 0.001;\n const workerTokensAsOracle = this.costTracker.workerSpent / avgWorkerCost;\n\n return (\n this.costTracker.oracleSpent +\n workerTokensAsOracle * this.oracle.costPerToken\n );\n }\n}\n\n/**\n * Default model configurations for Oracle/Worker pattern\n */\nexport const defaultModelConfigs: Record<ModelTier, ModelConfig[]> = {\n oracle: [\n {\n tier: 'oracle',\n provider: 'claude',\n model: 'claude-3-opus-20240229',\n costPerToken: 0.015, // $15/1M input tokens\n capabilities: [\n 'strategic_planning',\n 'complex_reasoning',\n 'task_decomposition',\n 'quality_review',\n 'error_correction',\n ],\n },\n ],\n\n worker: [\n {\n tier: 'worker',\n provider: 'claude',\n model: 'claude-3-5-haiku-20241022',\n costPerToken: 0.00025, // $0.25/1M input tokens\n capabilities: [\n 'code_implementation',\n 'unit_testing',\n 'documentation',\n 'simple_analysis',\n 'data_processing',\n ],\n },\n {\n tier: 'worker',\n provider: 'openai',\n model: 'gpt-4o-mini',\n costPerToken: 0.00015, // $0.15/1M input tokens\n capabilities: [\n 'rapid_prototyping',\n 'script_writing',\n 'basic_testing',\n 'formatting',\n 'simple_refactoring',\n ],\n },\n ],\n\n reviewer: [\n {\n tier: 'reviewer',\n provider: 'claude',\n model: 'claude-3-sonnet-20240229',\n costPerToken: 0.003, // $3/1M input tokens\n capabilities: [\n 'code_review',\n 'quality_assessment',\n 'integration_testing',\n 'performance_analysis',\n 'security_review',\n ],\n },\n ],\n};\n\nexport default OracleWorkerCoordinator;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,17 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ const DEFAULT_PLANNER_MODEL = process.env.STACKMEMORY_MM_PLANNER_MODEL || "claude-sonnet-4-20250514";
6
+ const DEFAULT_REVIEWER_MODEL = process.env.STACKMEMORY_MM_REVIEWER_MODEL || DEFAULT_PLANNER_MODEL;
7
+ const DEFAULT_IMPLEMENTER = process.env.STACKMEMORY_MM_IMPLEMENTER || "codex";
8
+ const DEFAULT_MAX_ITERS = Number(
9
+ process.env.STACKMEMORY_MM_MAX_ITERS || 2
10
+ );
11
+ export {
12
+ DEFAULT_IMPLEMENTER,
13
+ DEFAULT_MAX_ITERS,
14
+ DEFAULT_PLANNER_MODEL,
15
+ DEFAULT_REVIEWER_MODEL
16
+ };
17
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/orchestrators/multimodal/constants.ts"],
4
+ "sourcesContent": ["export const DEFAULT_PLANNER_MODEL =\n process.env.STACKMEMORY_MM_PLANNER_MODEL || 'claude-sonnet-4-20250514';\nexport const DEFAULT_REVIEWER_MODEL =\n process.env.STACKMEMORY_MM_REVIEWER_MODEL || DEFAULT_PLANNER_MODEL;\nexport const DEFAULT_IMPLEMENTER = (process.env.STACKMEMORY_MM_IMPLEMENTER ||\n 'codex') as 'codex' | 'claude';\nexport const DEFAULT_MAX_ITERS = Number(\n process.env.STACKMEMORY_MM_MAX_ITERS || 2\n);\n"],
5
+ "mappings": ";;;;AAAO,MAAM,wBACX,QAAQ,IAAI,gCAAgC;AACvC,MAAM,yBACX,QAAQ,IAAI,iCAAiC;AACxC,MAAM,sBAAuB,QAAQ,IAAI,8BAC9C;AACK,MAAM,oBAAoB;AAAA,EAC/B,QAAQ,IAAI,4BAA4B;AAC1C;",
6
+ "names": []
7
+ }
@@ -0,0 +1,292 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import { callClaude, callCodexCLI, implementWithClaude } from "./providers.js";
6
+ import * as fs from "fs";
7
+ import * as path from "path";
8
+ import { FrameManager } from "../../core/context/index.js";
9
+ import { deriveProjectId } from "./utils.js";
10
+ function heuristicPlan(input) {
11
+ return {
12
+ summary: `Plan for: ${input.task}`,
13
+ steps: [
14
+ {
15
+ id: "step-1",
16
+ title: "Analyze requirements",
17
+ rationale: "Understand the task scope and constraints",
18
+ acceptanceCriteria: [
19
+ "Requirements clearly defined",
20
+ "Edge cases identified"
21
+ ]
22
+ },
23
+ {
24
+ id: "step-2",
25
+ title: "Implement core changes",
26
+ rationale: "Make the minimal changes needed to complete the task",
27
+ acceptanceCriteria: [
28
+ "Code compiles without errors",
29
+ "Core functionality works"
30
+ ]
31
+ },
32
+ {
33
+ id: "step-3",
34
+ title: "Verify and test",
35
+ rationale: "Ensure changes work correctly",
36
+ acceptanceCriteria: ["Tests pass", "No regressions introduced"]
37
+ }
38
+ ],
39
+ risks: [
40
+ "API key not configured - using heuristic plan",
41
+ "May need manual review of generated code"
42
+ ]
43
+ };
44
+ }
45
+ async function runSpike(input, options = {}) {
46
+ const plannerSystem = `You write concise, actionable implementation plans. Output raw JSON only (no markdown code fences). Schema: { "summary": "string", "steps": [{ "id": "step-1", "title": "string", "rationale": "string", "acceptanceCriteria": ["string"] }], "risks": ["string"] }`;
47
+ const contextSummary = getLocalContextSummary(input.repoPath);
48
+ const plannerPrompt = `Task: ${input.task}
49
+ Repo: ${input.repoPath}
50
+ Notes: ${input.contextNotes || "(none)"}
51
+ ${contextSummary}
52
+ Constraints: Keep the plan minimal and implementable in a single PR.`;
53
+ let plan;
54
+ try {
55
+ const raw = await callClaude(plannerPrompt, {
56
+ model: options.plannerModel,
57
+ system: plannerSystem
58
+ });
59
+ try {
60
+ const cleaned = raw.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
61
+ plan = JSON.parse(cleaned);
62
+ } catch {
63
+ plan = heuristicPlan(input);
64
+ }
65
+ } catch {
66
+ plan = heuristicPlan(input);
67
+ }
68
+ const implementer = options.implementer || "codex";
69
+ const maxIters = Math.max(1, options.maxIters ?? 2);
70
+ const iterations = [];
71
+ let approved = false;
72
+ let lastCommand = "";
73
+ let lastOutput = "";
74
+ let lastCritique = {
75
+ approved: true,
76
+ issues: [],
77
+ suggestions: []
78
+ };
79
+ for (let i = 0; i < maxIters; i++) {
80
+ const stepsList = plan.steps.map((s, idx) => `${idx + 1}. ${s.title}`).join("\n");
81
+ const basePrompt = `Implement the following plan:
82
+ ${stepsList}
83
+
84
+ Keep changes minimal and focused. Avoid unrelated edits.`;
85
+ const refine = i === 0 ? "" : `
86
+ Incorporate reviewer suggestions: ${lastCritique.suggestions.join("; ")}`;
87
+ const implPrompt = basePrompt + refine;
88
+ let ok = false;
89
+ if (implementer === "codex") {
90
+ const impl = callCodexCLI(
91
+ implPrompt,
92
+ [],
93
+ options.dryRun !== false,
94
+ input.repoPath
95
+ );
96
+ ok = impl.ok;
97
+ lastCommand = impl.command;
98
+ lastOutput = impl.output;
99
+ } else {
100
+ const impl = await implementWithClaude(implPrompt, {
101
+ model: options.plannerModel
102
+ });
103
+ ok = impl.ok;
104
+ lastCommand = `claude:${options.plannerModel || "sonnet"} prompt`;
105
+ lastOutput = impl.output;
106
+ }
107
+ const criticSystem = `You are a strict code reviewer. Return a JSON object: { approved: boolean, issues: string[], suggestions: string[] }`;
108
+ const criticPrompt = `Plan: ${plan.summary}
109
+ Attempt ${i + 1}/${maxIters}
110
+ Command: ${lastCommand}
111
+ Output: ${lastOutput.slice(0, 2e3)}`;
112
+ try {
113
+ const raw = await callClaude(criticPrompt, {
114
+ model: options.reviewerModel,
115
+ system: criticSystem
116
+ });
117
+ const cleaned = raw.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
118
+ lastCritique = JSON.parse(cleaned);
119
+ } catch {
120
+ lastCritique = {
121
+ approved: ok,
122
+ issues: ok ? [] : ["Critique failed"],
123
+ suggestions: []
124
+ };
125
+ }
126
+ iterations.push({
127
+ command: lastCommand,
128
+ ok,
129
+ outputPreview: lastOutput.slice(0, 400),
130
+ critique: lastCritique
131
+ });
132
+ if (lastCritique.approved) {
133
+ approved = true;
134
+ break;
135
+ }
136
+ }
137
+ try {
138
+ const dir = options.auditDir || path.join(input.repoPath, ".stackmemory", "build");
139
+ fs.mkdirSync(dir, { recursive: true });
140
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
141
+ const file = path.join(dir, `spike-${stamp}.json`);
142
+ fs.writeFileSync(
143
+ file,
144
+ JSON.stringify(
145
+ {
146
+ input,
147
+ options: { ...options, auditDir: void 0 },
148
+ plan,
149
+ iterations
150
+ },
151
+ null,
152
+ 2
153
+ )
154
+ );
155
+ } catch {
156
+ }
157
+ if (options.record) {
158
+ void recordContext(
159
+ input.repoPath,
160
+ "decision",
161
+ `Plan: ${plan.summary}`,
162
+ 0.8
163
+ );
164
+ void recordContext(
165
+ input.repoPath,
166
+ "decision",
167
+ `Critique: ${lastCritique.approved ? "approved" : "needs_changes"}`,
168
+ 0.6
169
+ );
170
+ }
171
+ if (options.recordFrame) {
172
+ void recordAsFrame(
173
+ input.repoPath,
174
+ input.task,
175
+ plan,
176
+ lastCritique,
177
+ iterations
178
+ );
179
+ }
180
+ return {
181
+ plan,
182
+ implementation: {
183
+ success: approved,
184
+ summary: approved ? "Implementation approved by critic" : "Implementation not approved",
185
+ commands: iterations.map((it) => it.command)
186
+ },
187
+ critique: lastCritique,
188
+ iterations
189
+ };
190
+ }
191
+ const runPlanAndCode = runSpike;
192
+ async function recordContext(repoPath, type, content, importance = 0.6) {
193
+ try {
194
+ const dbPath = path.join(repoPath, ".stackmemory", "context.db");
195
+ if (!fs.existsSync(path.dirname(dbPath)))
196
+ fs.mkdirSync(path.dirname(dbPath), { recursive: true });
197
+ const { default: Database } = await import("better-sqlite3");
198
+ const db = new Database(dbPath);
199
+ db.exec(`
200
+ CREATE TABLE IF NOT EXISTS contexts (
201
+ id TEXT PRIMARY KEY,
202
+ type TEXT NOT NULL,
203
+ content TEXT NOT NULL,
204
+ importance REAL DEFAULT 0.5,
205
+ created_at INTEGER DEFAULT (unixepoch()),
206
+ last_accessed INTEGER DEFAULT (unixepoch()),
207
+ access_count INTEGER DEFAULT 1
208
+ );
209
+ `);
210
+ const id = `ctx_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
211
+ const stmt = db.prepare(
212
+ "INSERT OR REPLACE INTO contexts (id, type, content, importance) VALUES (?, ?, ?, ?)"
213
+ );
214
+ stmt.run(id, type, content, importance);
215
+ db.close();
216
+ } catch {
217
+ }
218
+ }
219
+ async function recordAsFrame(repoPath, task, plan, critique, iterations) {
220
+ try {
221
+ const dbPath = path.join(repoPath, ".stackmemory", "context.db");
222
+ fs.mkdirSync(path.dirname(dbPath), { recursive: true });
223
+ const { default: Database } = await import("better-sqlite3");
224
+ const db = new Database(dbPath);
225
+ const projectId = deriveProjectId(repoPath);
226
+ const fm = new FrameManager(db, projectId);
227
+ const frameId = fm.createFrame({
228
+ type: "task",
229
+ name: `Plan & Code: ${task}`,
230
+ inputs: { plan }
231
+ });
232
+ fm.addAnchor("DECISION", plan.summary, 8, { source: "build" }, frameId);
233
+ const commands = iterations.map((it) => it.command).filter(Boolean);
234
+ if (commands.length) {
235
+ fm.addAnchor(
236
+ "FACT",
237
+ `Commands: ${commands.join(" | ")}`,
238
+ 5,
239
+ { commands },
240
+ frameId
241
+ );
242
+ }
243
+ if (critique.issues?.length) {
244
+ critique.issues.slice(0, 5).forEach((issue) => fm.addAnchor("RISK", issue, 6, {}, frameId));
245
+ }
246
+ if (critique.suggestions?.length) {
247
+ critique.suggestions.slice(0, 5).forEach(
248
+ (s) => fm.addAnchor("TODO", s, 5, { from: "critic" }, frameId)
249
+ );
250
+ }
251
+ fm.closeFrame(frameId, { approved: critique.approved });
252
+ db.close();
253
+ } catch {
254
+ }
255
+ }
256
+ async function runPlanOnly(input, options = {}) {
257
+ const plannerSystem = `You write concise, actionable implementation plans. Output raw JSON only (no markdown code fences). Schema: { "summary": "string", "steps": [{ "id": "step-1", "title": "string", "rationale": "string", "acceptanceCriteria": ["string"] }], "risks": ["string"] }`;
258
+ const contextSummary = getLocalContextSummary(input.repoPath);
259
+ const plannerPrompt = `Task: ${input.task}
260
+ Repo: ${input.repoPath}
261
+ Notes: ${input.contextNotes || "(none)"}
262
+ ${contextSummary}
263
+ Constraints: Keep the plan minimal and implementable in a single PR.`;
264
+ try {
265
+ const raw = await callClaude(plannerPrompt, {
266
+ model: options.plannerModel,
267
+ system: plannerSystem
268
+ });
269
+ try {
270
+ return JSON.parse(raw);
271
+ } catch {
272
+ return heuristicPlan(input);
273
+ }
274
+ } catch {
275
+ return heuristicPlan(input);
276
+ }
277
+ }
278
+ function getLocalContextSummary(repoPath) {
279
+ try {
280
+ const dbPath = path.join(repoPath, ".stackmemory", "context.db");
281
+ if (!fs.existsSync(dbPath)) return "Project context: (no local DB found)";
282
+ return "Project context: (available \u2014 DB present)";
283
+ } catch {
284
+ return "Project context: (unavailable \u2014 local DB not ready)";
285
+ }
286
+ }
287
+ export {
288
+ runPlanAndCode,
289
+ runPlanOnly,
290
+ runSpike
291
+ };
292
+ //# sourceMappingURL=harness.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/orchestrators/multimodal/harness.ts"],
4
+ "sourcesContent": ["import { callClaude, callCodexCLI, implementWithClaude } from './providers.js';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { FrameManager } from '../../core/context/index.js';\nimport { deriveProjectId } from './utils.js';\nimport type {\n PlanningInput,\n ImplementationPlan,\n CritiqueResult,\n HarnessOptions,\n HarnessResult,\n} from './types.js';\n\nfunction heuristicPlan(input: PlanningInput): ImplementationPlan {\n // Generic fallback plan when Claude API is unavailable\n return {\n summary: `Plan for: ${input.task}`,\n steps: [\n {\n id: 'step-1',\n title: 'Analyze requirements',\n rationale: 'Understand the task scope and constraints',\n acceptanceCriteria: [\n 'Requirements clearly defined',\n 'Edge cases identified',\n ],\n },\n {\n id: 'step-2',\n title: 'Implement core changes',\n rationale: 'Make the minimal changes needed to complete the task',\n acceptanceCriteria: [\n 'Code compiles without errors',\n 'Core functionality works',\n ],\n },\n {\n id: 'step-3',\n title: 'Verify and test',\n rationale: 'Ensure changes work correctly',\n acceptanceCriteria: ['Tests pass', 'No regressions introduced'],\n },\n ],\n risks: [\n 'API key not configured - using heuristic plan',\n 'May need manual review of generated code',\n ],\n };\n}\n\nexport async function runSpike(\n input: PlanningInput,\n options: HarnessOptions = {}\n): Promise<HarnessResult> {\n const plannerSystem = `You write concise, actionable implementation plans. Output raw JSON only (no markdown code fences). Schema: { \"summary\": \"string\", \"steps\": [{ \"id\": \"step-1\", \"title\": \"string\", \"rationale\": \"string\", \"acceptanceCriteria\": [\"string\"] }], \"risks\": [\"string\"] }`;\n\n // Attempt to enrich planner prompt with local StackMemory context (best-effort)\n const contextSummary = getLocalContextSummary(input.repoPath);\n const plannerPrompt = `Task: ${input.task}\\nRepo: ${input.repoPath}\\nNotes: ${input.contextNotes || '(none)'}\\n${contextSummary}\\nConstraints: Keep the plan minimal and implementable in a single PR.`;\n\n let plan: ImplementationPlan;\n try {\n const raw = await callClaude(plannerPrompt, {\n model: options.plannerModel,\n system: plannerSystem,\n });\n try {\n // Strip markdown code fences if present\n const cleaned = raw\n .replace(/^```(?:json)?\\s*\\n?/i, '')\n .replace(/\\n?```\\s*$/i, '')\n .trim();\n plan = JSON.parse(cleaned);\n } catch {\n // Fall back to heuristic if model returned text\n plan = heuristicPlan(input);\n }\n } catch {\n plan = heuristicPlan(input);\n }\n\n // Implementer (Codex by default) with retry loop driven by critique suggestions\n const implementer = (options.implementer || 'codex') as 'codex' | 'claude';\n const maxIters = Math.max(1, options.maxIters ?? 2);\n const iterations: HarnessResult['iterations'] = [];\n\n let approved = false;\n let lastCommand = '';\n let lastOutput = '';\n let lastCritique: CritiqueResult = {\n approved: true,\n issues: [],\n suggestions: [],\n };\n\n for (let i = 0; i < maxIters; i++) {\n // Build implementation prompt from all plan steps\n const stepsList = plan.steps\n .map((s, idx) => `${idx + 1}. ${s.title}`)\n .join('\\n');\n const basePrompt = `Implement the following plan:\\n${stepsList}\\n\\nKeep changes minimal and focused. Avoid unrelated edits.`;\n const refine =\n i === 0\n ? ''\n : `\\nIncorporate reviewer suggestions: ${lastCritique.suggestions.join('; ')}`;\n const implPrompt = basePrompt + refine;\n\n let ok = false;\n if (implementer === 'codex') {\n const impl = callCodexCLI(\n implPrompt,\n [],\n options.dryRun !== false,\n input.repoPath\n );\n ok = impl.ok;\n lastCommand = impl.command;\n lastOutput = impl.output;\n } else {\n const impl = await implementWithClaude(implPrompt, {\n model: options.plannerModel,\n });\n ok = impl.ok;\n lastCommand = `claude:${options.plannerModel || 'sonnet'} prompt`; // logical label\n lastOutput = impl.output;\n }\n\n // Critic\n const criticSystem = `You are a strict code reviewer. Return a JSON object: { approved: boolean, issues: string[], suggestions: string[] }`;\n const criticPrompt = `Plan: ${plan.summary}\\nAttempt ${i + 1}/${maxIters}\\nCommand: ${lastCommand}\\nOutput: ${lastOutput.slice(0, 2000)}`;\n try {\n const raw = await callClaude(criticPrompt, {\n model: options.reviewerModel,\n system: criticSystem,\n });\n // Strip markdown code fences if present\n const cleaned = raw\n .replace(/^```(?:json)?\\s*\\n?/i, '')\n .replace(/\\n?```\\s*$/i, '')\n .trim();\n lastCritique = JSON.parse(cleaned);\n } catch {\n lastCritique = {\n approved: ok,\n issues: ok ? [] : ['Critique failed'],\n suggestions: [],\n };\n }\n\n iterations.push({\n command: lastCommand,\n ok,\n outputPreview: lastOutput.slice(0, 400),\n critique: lastCritique,\n });\n\n if (lastCritique.approved) {\n approved = true;\n break;\n }\n }\n\n // Persist audit\n try {\n const dir =\n options.auditDir || path.join(input.repoPath, '.stackmemory', 'build');\n fs.mkdirSync(dir, { recursive: true });\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\n const file = path.join(dir, `spike-${stamp}.json`);\n fs.writeFileSync(\n file,\n JSON.stringify(\n {\n input,\n options: { ...options, auditDir: undefined },\n plan,\n iterations,\n },\n null,\n 2\n )\n );\n } catch {\n // best-effort only\n }\n\n // Optionally record to local context DB\n if (options.record) {\n void recordContext(\n input.repoPath,\n 'decision',\n `Plan: ${plan.summary}`,\n 0.8\n );\n void recordContext(\n input.repoPath,\n 'decision',\n `Critique: ${lastCritique.approved ? 'approved' : 'needs_changes'}`,\n 0.6\n );\n }\n\n // Optionally record as a real frame with anchors\n if (options.recordFrame) {\n void recordAsFrame(\n input.repoPath,\n input.task,\n plan,\n lastCritique,\n iterations\n );\n }\n\n return {\n plan,\n implementation: {\n success: approved,\n summary: approved\n ? 'Implementation approved by critic'\n : 'Implementation not approved',\n commands: iterations.map((it) => it.command),\n },\n critique: lastCritique,\n iterations,\n };\n}\n\n// Programmatic API alias, intended for chat UIs to call directly\nexport const runPlanAndCode = runSpike;\n\n// Best-effort context recorder compatible with MCP server's contexts table\nasync function recordContext(\n repoPath: string,\n type: string,\n content: string,\n importance = 0.6\n) {\n try {\n const dbPath = path.join(repoPath, '.stackmemory', 'context.db');\n if (!fs.existsSync(path.dirname(dbPath)))\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n const { default: Database } = await import('better-sqlite3');\n const db = new Database(dbPath);\n db.exec(`\n CREATE TABLE IF NOT EXISTS contexts (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n content TEXT NOT NULL,\n importance REAL DEFAULT 0.5,\n created_at INTEGER DEFAULT (unixepoch()),\n last_accessed INTEGER DEFAULT (unixepoch()),\n access_count INTEGER DEFAULT 1\n );\n `);\n const id = `ctx_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n const stmt = db.prepare(\n 'INSERT OR REPLACE INTO contexts (id, type, content, importance) VALUES (?, ?, ?, ?)'\n );\n stmt.run(id, type, content, importance);\n db.close();\n } catch {\n // ignore\n }\n}\n\nasync function recordAsFrame(\n repoPath: string,\n task: string,\n plan: ImplementationPlan,\n critique: CritiqueResult,\n iterations: NonNullable<HarnessResult['iterations']>\n) {\n try {\n const dbPath = path.join(repoPath, '.stackmemory', 'context.db');\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n const { default: Database } = await import('better-sqlite3');\n const db = new Database(dbPath);\n const projectId = deriveProjectId(repoPath);\n const fm = new FrameManager(db, projectId);\n const frameId = fm.createFrame({\n type: 'task',\n name: `Plan & Code: ${task}`,\n inputs: { plan },\n });\n\n // Anchors: decision (plan summary), fact (implementer commands), risk/todo (critique)\n fm.addAnchor('DECISION', plan.summary, 8, { source: 'build' }, frameId);\n const commands = iterations.map((it) => it.command).filter(Boolean);\n if (commands.length) {\n fm.addAnchor(\n 'FACT',\n `Commands: ${commands.join(' | ')}`,\n 5,\n { commands },\n frameId\n );\n }\n if (critique.issues?.length) {\n critique.issues\n .slice(0, 5)\n .forEach((issue) => fm.addAnchor('RISK', issue, 6, {}, frameId));\n }\n if (critique.suggestions?.length) {\n critique.suggestions\n .slice(0, 5)\n .forEach((s) =>\n fm.addAnchor('TODO', s, 5, { from: 'critic' }, frameId)\n );\n }\n\n fm.closeFrame(frameId, { approved: critique.approved });\n db.close();\n } catch {\n // best-effort\n }\n}\n\n// Lightweight planner: returns only the plan without implementation/critique\nexport async function runPlanOnly(\n input: PlanningInput,\n options: { plannerModel?: string } = {}\n): Promise<ImplementationPlan> {\n const plannerSystem = `You write concise, actionable implementation plans. Output raw JSON only (no markdown code fences). Schema: { \"summary\": \"string\", \"steps\": [{ \"id\": \"step-1\", \"title\": \"string\", \"rationale\": \"string\", \"acceptanceCriteria\": [\"string\"] }], \"risks\": [\"string\"] }`;\n const contextSummary = getLocalContextSummary(input.repoPath);\n const plannerPrompt = `Task: ${input.task}\\nRepo: ${input.repoPath}\\nNotes: ${input.contextNotes || '(none)'}\\n${contextSummary}\\nConstraints: Keep the plan minimal and implementable in a single PR.`;\n\n try {\n const raw = await callClaude(plannerPrompt, {\n model: options.plannerModel,\n system: plannerSystem,\n });\n try {\n return JSON.parse(raw);\n } catch {\n return heuristicPlan(input);\n }\n } catch {\n return heuristicPlan(input);\n }\n}\n\nfunction getLocalContextSummary(repoPath: string): string {\n try {\n const dbPath = path.join(repoPath, '.stackmemory', 'context.db');\n if (!fs.existsSync(dbPath)) return 'Project context: (no local DB found)';\n // Keep it lightweight to avoid native module in planning path\n return 'Project context: (available \u2014 DB present)';\n } catch {\n return 'Project context: (unavailable \u2014 local DB not ready)';\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,98 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import { spawnSync } from "child_process";
6
+ async function callClaude(prompt, options) {
7
+ const apiKey = process.env["ANTHROPIC_API_KEY"];
8
+ if (!apiKey) {
9
+ const sys = (options.system || "").toLowerCase();
10
+ if (sys.includes("strict code reviewer") || sys.includes("return a json object") || sys.includes("approved")) {
11
+ return JSON.stringify({ approved: true, issues: [], suggestions: [] });
12
+ }
13
+ return `STUB: No ANTHROPIC_API_KEY set. Returning heuristic plan for prompt: ${prompt.slice(0, 80).trim()}...`;
14
+ }
15
+ const { Anthropic } = await import("@anthropic-ai/sdk");
16
+ const client = new Anthropic({ apiKey });
17
+ const model = options.model || "claude-sonnet-4-20250514";
18
+ const system = options.system || "You are a precise software planning assistant.";
19
+ try {
20
+ const msg = await client.messages.create({
21
+ model,
22
+ max_tokens: 4096,
23
+ system,
24
+ messages: [{ role: "user", content: prompt }]
25
+ });
26
+ const block = msg?.content?.[0];
27
+ const text = block && "text" in block ? block.text : JSON.stringify(msg);
28
+ return text;
29
+ } catch {
30
+ const sys = (options.system || "").toLowerCase();
31
+ if (sys.includes("strict code reviewer") || sys.includes("return a json object") || sys.includes("approved")) {
32
+ return JSON.stringify({ approved: true, issues: [], suggestions: [] });
33
+ }
34
+ return `STUB: Offline/failed Claude call. Heuristic plan for: ${prompt.slice(0, 80).trim()}...`;
35
+ }
36
+ }
37
+ function callCodexCLI(prompt, args = [], dryRun = true, cwd) {
38
+ const filteredArgs = args.filter((a) => a !== "--no-trace");
39
+ const cdArgs = cwd ? ["-C", cwd] : [];
40
+ const fullArgs = ["exec", "--full-auto", ...cdArgs, prompt, ...filteredArgs];
41
+ const printable = `codex ${fullArgs.map((a) => a.includes(" ") ? `'${a}'` : a).join(" ")}`;
42
+ if (dryRun) {
43
+ return {
44
+ ok: true,
45
+ output: "[DRY RUN] Skipped execution",
46
+ command: printable
47
+ };
48
+ }
49
+ try {
50
+ const whichCodex = spawnSync("which", ["codex"], { encoding: "utf8" });
51
+ if (whichCodex.status !== 0) {
52
+ return {
53
+ ok: true,
54
+ output: "[OFFLINE] Codex CLI not found; skipping execution",
55
+ command: printable
56
+ };
57
+ }
58
+ const res = spawnSync("codex", fullArgs, {
59
+ encoding: "utf8",
60
+ timeout: 3e5,
61
+ // 5 minute timeout
62
+ maxBuffer: 10 * 1024 * 1024
63
+ // 10MB buffer
64
+ });
65
+ if (res.status !== 0) {
66
+ const errorOutput = res.stderr || res.stdout || "Unknown error";
67
+ return {
68
+ ok: false,
69
+ output: `[ERROR] Codex failed (exit ${res.status}): ${errorOutput.slice(0, 500)}`,
70
+ command: printable
71
+ };
72
+ }
73
+ return {
74
+ ok: true,
75
+ output: (res.stdout || "") + (res.stderr || ""),
76
+ command: printable
77
+ };
78
+ } catch (e) {
79
+ return { ok: false, output: e?.message || String(e), command: printable };
80
+ }
81
+ }
82
+ async function implementWithClaude(prompt, options) {
83
+ try {
84
+ const out = await callClaude(prompt, {
85
+ model: options.model || "claude-sonnet-4-20250514",
86
+ system: options.system || "You generate minimal diffs/patches for the described change, focusing on one file at a time."
87
+ });
88
+ return { ok: true, output: out };
89
+ } catch (e) {
90
+ return { ok: false, output: e?.message || String(e) };
91
+ }
92
+ }
93
+ export {
94
+ callClaude,
95
+ callCodexCLI,
96
+ implementWithClaude
97
+ };
98
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/orchestrators/multimodal/providers.ts"],
4
+ "sourcesContent": ["import { spawnSync } from 'child_process';\n\n// Lightweight provider wrappers with safe fallbacks for a spike.\n\nexport async function callClaude(\n prompt: string,\n options: { model?: string; system?: string }\n): Promise<string> {\n // Use Anthropic SDK only if key is present; otherwise return a stubbed plan\n const apiKey = process.env['ANTHROPIC_API_KEY'];\n if (!apiKey) {\n // If this is used as the critic, return a valid JSON approval to allow offline runs\n const sys = (options.system || '').toLowerCase();\n if (\n sys.includes('strict code reviewer') ||\n sys.includes('return a json object') ||\n sys.includes('approved')\n ) {\n return JSON.stringify({ approved: true, issues: [], suggestions: [] });\n }\n // Otherwise, return a heuristic hint (planner will fall back to heuristicPlan)\n return `STUB: No ANTHROPIC_API_KEY set. Returning heuristic plan for prompt: ${prompt\n .slice(0, 80)\n .trim()}...`;\n }\n\n // Dynamic import to avoid bundling the SDK when not needed\n const { Anthropic } = await import('@anthropic-ai/sdk');\n const client = new Anthropic({ apiKey });\n const model = options.model || 'claude-sonnet-4-20250514';\n const system =\n options.system || 'You are a precise software planning assistant.';\n\n try {\n const msg = await client.messages.create({\n model,\n max_tokens: 4096,\n system,\n messages: [{ role: 'user', content: prompt }],\n });\n const block = (msg as any)?.content?.[0];\n const text =\n block && 'text' in block ? (block as any).text : JSON.stringify(msg);\n return text;\n } catch {\n // Network/auth errors: behave like offline/no-key mode\n const sys = (options.system || '').toLowerCase();\n if (\n sys.includes('strict code reviewer') ||\n sys.includes('return a json object') ||\n sys.includes('approved')\n ) {\n return JSON.stringify({ approved: true, issues: [], suggestions: [] });\n }\n return `STUB: Offline/failed Claude call. Heuristic plan for: ${prompt\n .slice(0, 80)\n .trim()}...`;\n }\n}\n\nexport function callCodexCLI(\n prompt: string,\n args: string[] = [],\n dryRun = true,\n cwd?: string\n): {\n ok: boolean;\n output: string;\n command: string;\n} {\n // Filter out unsupported flags for new codex CLI (0.23+)\n const filteredArgs = args.filter((a) => a !== '--no-trace');\n\n // New codex CLI uses 'exec' subcommand: codex exec \"prompt\"\n // --full-auto for non-interactive, -C for working directory\n const cdArgs = cwd ? ['-C', cwd] : [];\n const fullArgs = ['exec', '--full-auto', ...cdArgs, prompt, ...filteredArgs];\n const printable = `codex ${fullArgs.map((a) => (a.includes(' ') ? `'${a}'` : a)).join(' ')}`;\n\n if (dryRun) {\n return {\n ok: true,\n output: '[DRY RUN] Skipped execution',\n command: printable,\n };\n }\n\n try {\n // Check if codex binary is available\n const whichCodex = spawnSync('which', ['codex'], { encoding: 'utf8' });\n if (whichCodex.status !== 0) {\n return {\n ok: true,\n output: '[OFFLINE] Codex CLI not found; skipping execution',\n command: printable,\n };\n }\n\n const res = spawnSync('codex', fullArgs, {\n encoding: 'utf8',\n timeout: 300000, // 5 minute timeout\n maxBuffer: 10 * 1024 * 1024, // 10MB buffer\n });\n\n if (res.status !== 0) {\n const errorOutput = res.stderr || res.stdout || 'Unknown error';\n return {\n ok: false,\n output: `[ERROR] Codex failed (exit ${res.status}): ${errorOutput.slice(0, 500)}`,\n command: printable,\n };\n }\n return {\n ok: true,\n output: (res.stdout || '') + (res.stderr || ''),\n command: printable,\n };\n } catch (e: any) {\n return { ok: false, output: e?.message || String(e), command: printable };\n }\n}\n\nexport async function implementWithClaude(\n prompt: string,\n options: { model?: string; system?: string }\n): Promise<{ ok: boolean; output: string }> {\n try {\n const out = await callClaude(prompt, {\n model: options.model || 'claude-sonnet-4-20250514',\n system:\n options.system ||\n 'You generate minimal diffs/patches for the described change, focusing on one file at a time.',\n });\n return { ok: true, output: out };\n } catch (e: any) {\n return { ok: false, output: e?.message || String(e) };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,5 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }