0xray 3.2.0 → 3.3.1

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 (36) hide show
  1. package/.opencode/codex.codex +1 -1
  2. package/dist/CHANGELOG.md +36 -0
  3. package/dist/core/features-config.js +3 -0
  4. package/dist/integrations/grok/grok-cli.js +6 -0
  5. package/dist/mcps/index.js +1 -0
  6. package/dist/mcps/knowledge-skills/skill-invocation.server.js +3 -2
  7. package/dist/mcps/knowledge-skills/storyteller.server.js +167 -0
  8. package/dist/mcps/orchestrator/config/agent-capabilities.js +30 -11
  9. package/dist/mcps/orchestrator/config/memory-routing-bridge.js +70 -0
  10. package/dist/mcps/orchestrator/execution/execution-planner.js +38 -8
  11. package/dist/mcps/orchestrator/handlers/task-handler.js +55 -2
  12. package/dist/mcps/researcher-confidence.js +92 -0
  13. package/dist/mcps/researcher.server.js +19 -3
  14. package/dist/memory-routing/index.js +4 -0
  15. package/dist/memory-routing/null-provider.js +63 -0
  16. package/dist/memory-routing/provider-loader.js +91 -0
  17. package/dist/memory-routing/provider-registry.js +40 -0
  18. package/dist/memory-routing/types.js +7 -0
  19. package/dist/memory-routing/validate-config.js +32 -0
  20. package/dist/nucleus/thin-dispatch.js +29 -1
  21. package/package.json +1 -1
  22. package/scripts/node/install-bridges.cjs +364 -0
  23. package/scripts/node/postinstall.cjs +24 -83
  24. package/scripts/node/setup.cjs +2 -6
  25. package/scripts/node/universal-version-manager.js +2 -2
  26. package/src/mcps/index.ts +1 -0
  27. package/src/mcps/knowledge-skills/skill-invocation.server.ts +3 -2
  28. package/src/mcps/knowledge-skills/storyteller.server.ts +206 -0
  29. package/src/mcps/orchestrator/config/agent-capabilities.ts +49 -14
  30. package/src/mcps/orchestrator/config/memory-routing-bridge.ts +80 -0
  31. package/src/mcps/orchestrator/execution/execution-planner.ts +49 -10
  32. package/src/mcps/orchestrator/handlers/task-handler.ts +71 -2
  33. package/src/mcps/orchestrator/types.ts +17 -0
  34. package/src/mcps/researcher-confidence.ts +144 -0
  35. package/src/mcps/researcher.server.ts +28 -3
  36. package/src/opencode/codex.codex +1 -1
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.2.0",
2
+ "version": "3.3.1",
3
3
  "terms": [
4
4
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
5
5
  ],
package/dist/CHANGELOG.md CHANGED
@@ -4,6 +4,42 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Conventional Commits](https://www.conventionalcommits.org/).
6
6
 
7
+ ## [3.3.0] - 2026-06-18
8
+
9
+ ### 🔄 Changes
10
+
11
+ ### 🔎 Other Changes
12
+ - Wire orchestrator confidence gate into execution planning (d7910b610)
13
+ - tweet: v3.3.0 release tweet — Pluggable Memory Routing (7fb6c9f70)
14
+
15
+ ---
16
+
17
+ ## [3.2.0] - 2026-06-17
18
+
19
+ ### 🔄 Changes
20
+
21
+ ### ✨ Features
22
+ - Orphan file resolution: 5 dead files deleted, ~39 files integrated under typecheck
23
+ - feat: 58 type errors fixed across 6 source files
24
+ - feat: pre-existing e2e failures fixed (OpenClaw 9/9, Grok CLI 62/0)
25
+ - feat: vitest config testTimeout added for processor-logger stability
26
+ - feat: pre-tool-use hook rewritten from skeleton to full hook with resonance/decision-matrix/JSON
27
+ - feat: SelfProposalEngine integrated under typecheck with metamorphosis type support
28
+
29
+ ### 🐛 Bug Fixes
30
+ - fix: postinstall e2e version assertions (3.1.1 → 0.5.2)
31
+ - fix: AGENTS.md session entry and test assertions cleaned
32
+ - fix: enforcement-gate fallback dynamic imports `as string` cast
33
+
34
+ ### ♻️ Refactoring
35
+ - chore: removed ~180 stale @version JSDoc tags from source files
36
+ - chore: cleaned stale version badges from README, AGENTS.md, docs-site docs
37
+ - chore: removed "xray 2.0" from command docs (26 files)
38
+ - chore: release.mjs checks npm view 0xray version (was xray)
39
+ - chore: release.mjs push target master → main
40
+
41
+ ---
42
+
7
43
  ## [3.1.1] - 2026-06-17
8
44
 
9
45
  ### 🔄 Changes
@@ -472,6 +472,9 @@ export class FeaturesConfigLoader {
472
472
  getInference() {
473
473
  return this.loadConfig().inference;
474
474
  }
475
+ getMemoryRouting() {
476
+ return this.loadConfig().memory_routing;
477
+ }
475
478
  getPublish() {
476
479
  return this.loadConfig().publish;
477
480
  }
@@ -55,6 +55,12 @@ export async function installForGrokCLI(options = {}) {
55
55
  console.log(`\x1b[32m✓ Synced ${skillsCopied} builtin skills to Grok plugin\x1b[0m`);
56
56
  }
57
57
  frameworkLogger.log('grok-integration', 'skills-synced', 'info', { count: skillsCopied });
58
+ // Grok Build / Cursor also reads ~/.grok/skills/ for agent_skills
59
+ const globalSkillsDir = path.join(home, '.grok', 'skills');
60
+ const globalCopied = syncBuiltinSkills(globalSkillsDir);
61
+ if (globalCopied > 0) {
62
+ console.log(`\x1b[32m✓ Synced ${globalCopied} builtin skills to ~/.grok/skills/\x1b[0m`);
63
+ }
58
64
  // Attempt auto-trust (best effort)
59
65
  try {
60
66
  execSync(`grok plugins trust "${targetPluginDir}"`, { stdio: 'ignore' });
@@ -40,6 +40,7 @@ export const MCP_SERVERS = [
40
40
  { serverName: "refactoring-strategies", sourceFile: "mcps/knowledge-skills/refactoring-strategies.server.ts", type: "knowledge-skill", registered: true, description: "Refactoring strategies" },
41
41
  { serverName: "security-audit", sourceFile: "mcps/knowledge-skills/security-audit.server.ts", type: "knowledge-skill", registered: true, description: "Security auditing" },
42
42
  { serverName: "seo-consultant", sourceFile: "mcps/knowledge-skills/seo-consultant.server.ts", type: "knowledge-skill", registered: false, description: "SEO consulting" },
43
+ { serverName: "storyteller", sourceFile: "mcps/knowledge-skills/storyteller.server.ts", type: "knowledge-skill", registered: false, description: "Reflections, sagas, and technical narratives" },
43
44
  { serverName: "session-management", sourceFile: "mcps/knowledge-skills/session-management.server.ts", type: "knowledge-skill", registered: true, description: "Session management" },
44
45
  { serverName: "skill-invocation", sourceFile: "mcps/knowledge-skills/skill-invocation.server.ts", type: "knowledge-skill", registered: true, description: "Skill invocation" },
45
46
  { serverName: "strategist", sourceFile: "mcps/knowledge-skills/strategist.server.ts", type: "knowledge-skill", registered: false, description: "Strategic planning" },
@@ -87,7 +87,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
87
87
  "strategist", "skill-invocation",
88
88
  ];
89
89
  const knowledgeSkills = [
90
- "architecture-patterns", "strategist", "tech-writer",
90
+ "architecture-patterns", "strategist", "tech-writer", "storyteller",
91
91
  "seo-consultant", "content-creator", "growth-strategist",
92
92
  "bug-triage-specialist", "log-monitor",
93
93
  "mobile-development", "git-workflow", "session-management",
@@ -132,6 +132,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
132
132
  "tech-writer": "documentation-generation",
133
133
  "frontend-ui-ux-engineer": "ui-ux-design",
134
134
  "frontend-engineer": "project-analysis",
135
+ "storyteller": "storyteller",
135
136
  };
136
137
  const resolvedSkill = skillAliases[skillName] || skillName;
137
138
  const availableServers = [
@@ -147,7 +148,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
147
148
  "git-workflow", "content-creator", "ui-ux-design",
148
149
  "multimodal-looker", "refactoring-strategies",
149
150
  "project-analysis", "testing-best-practices",
150
- "architecture-patterns",
151
+ "architecture-patterns", "storyteller",
151
152
  ];
152
153
  if (!availableServers.includes(resolvedSkill)) {
153
154
  return {
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Storyteller MCP Server
3
+ *
4
+ * Returns storyteller SKILL.md guidance plus a session-aware writing prompt.
5
+ * The host LLM writes the story; this server supplies the contract.
6
+ */
7
+ import { execSync } from 'node:child_process';
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
9
+ import { dirname, join } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { XrayKnowledgeSkillBase } from '../shared/knowledge-skill-base.js';
12
+ const STORY_TYPES = ['reflection', 'saga', 'journey', 'narrative'];
13
+ function resolveSkillMd() {
14
+ const here = dirname(fileURLToPath(import.meta.url));
15
+ const candidates = [
16
+ join(here, '../../../skills/storyteller/SKILL.md'),
17
+ join(here, '../../skills/storyteller/SKILL.md'),
18
+ join(process.cwd(), 'node_modules/0xray/dist/skills/storyteller/SKILL.md'),
19
+ join(process.cwd(), 'node_modules/xray/dist/skills/storyteller/SKILL.md'),
20
+ ];
21
+ for (const path of candidates) {
22
+ if (existsSync(path)) {
23
+ return readFileSync(path, 'utf-8');
24
+ }
25
+ }
26
+ return '# Storyteller\n\nWrite warmly candid technical reflections with scene-first openings.';
27
+ }
28
+ function getStoryMeta(storyType) {
29
+ const defaults = {
30
+ reflection: {
31
+ location: 'docs/reflections/',
32
+ min_words: 2000,
33
+ ideal_words: 5000,
34
+ framework: 'three_act_structure',
35
+ },
36
+ saga: {
37
+ location: 'docs/reflections/deep/',
38
+ min_words: 5000,
39
+ ideal_words: 15000,
40
+ framework: 'hero_journey',
41
+ },
42
+ journey: {
43
+ location: 'docs/reflections/deep/',
44
+ min_words: 1500,
45
+ ideal_words: 4000,
46
+ framework: 'three_act_structure',
47
+ },
48
+ narrative: {
49
+ location: 'docs/reflections/',
50
+ min_words: 1000,
51
+ ideal_words: 3000,
52
+ framework: 'three_act_structure',
53
+ },
54
+ };
55
+ return defaults[storyType];
56
+ }
57
+ function gitContext() {
58
+ try {
59
+ const commits = execSync('git log --oneline -20 2>/dev/null', { encoding: 'utf-8' });
60
+ const files = execSync('git diff --name-only HEAD~10 2>/dev/null || git ls-files 2>/dev/null | head -50', { encoding: 'utf-8' });
61
+ return `Recent commits:\n${commits}\n\nRecent files:\n${files}`;
62
+ }
63
+ catch {
64
+ return 'No git context available in this workspace.';
65
+ }
66
+ }
67
+ function buildPrompt(storyType, title, meta, extraContext) {
68
+ const contextBlock = extraContext
69
+ ? `\n## Provided context\n${JSON.stringify(extraContext, null, 2)}\n`
70
+ : '';
71
+ return `Write a ${storyType} titled "${title}".
72
+
73
+ ## Requirements
74
+ - Framework: ${meta.framework}
75
+ - Target length: ${meta.ideal_words} words (minimum: ${meta.min_words})
76
+ - Save to: ${meta.location}
77
+ - Follow storyteller SKILL.md voice (warmly candid, scene-first, no executive summary)
78
+ - Include Key Takeaways and What Next sections
79
+
80
+ ## Session / repo context
81
+ ${gitContext()}
82
+ ${contextBlock}
83
+
84
+ Write the complete ${storyType} now.`;
85
+ }
86
+ function writeStoryTool(storyType, args) {
87
+ const meta = getStoryMeta(storyType);
88
+ if (args.framework)
89
+ meta.framework = args.framework;
90
+ const title = args.title ??
91
+ `${storyType.charAt(0).toUpperCase() + storyType.slice(1)} - ${new Date().toISOString().split('T')[0]}`;
92
+ const skillMd = resolveSkillMd();
93
+ const prompt = buildPrompt(storyType, title, meta, args.context);
94
+ const slug = title
95
+ .toLowerCase()
96
+ .replace(/[^a-z0-9]+/g, '-')
97
+ .replace(/^-|-$/g, '');
98
+ const filename = `${storyType}-${slug}-${new Date().toISOString().split('T')[0]}.md`;
99
+ const outputPath = args.output ?? join(meta.location, filename);
100
+ const outputDir = join(process.cwd(), dirname(outputPath));
101
+ if (!existsSync(outputDir))
102
+ mkdirSync(outputDir, { recursive: true });
103
+ const fullPath = join(process.cwd(), outputPath);
104
+ const frontmatter = `---
105
+ story_type: ${storyType}
106
+ title: "${title}"
107
+ framework: ${meta.framework}
108
+ target_words: ${meta.ideal_words}
109
+ ---
110
+
111
+ `;
112
+ writeFileSync(fullPath, `${frontmatter}\n${prompt}\n`, 'utf-8');
113
+ return {
114
+ content: [
115
+ {
116
+ type: 'text',
117
+ text: [
118
+ `Storyteller ${storyType} brief prepared.`,
119
+ `Output template: ${outputPath}`,
120
+ '',
121
+ '--- SKILL (excerpt) ---',
122
+ skillMd.slice(0, 4000),
123
+ skillMd.length > 4000 ? '\n...(truncated; full SKILL.md on disk)' : '',
124
+ '',
125
+ '--- WRITING PROMPT ---',
126
+ prompt,
127
+ '',
128
+ 'Host LLM: write the full story into the output path using the prompt above.',
129
+ ].join('\n'),
130
+ },
131
+ ],
132
+ };
133
+ }
134
+ class StorytellerServer extends XrayKnowledgeSkillBase {
135
+ constructor() {
136
+ super('storyteller', '1.0.0');
137
+ const writeSchema = {
138
+ type: 'object',
139
+ properties: {
140
+ title: { type: 'string', description: 'Story title' },
141
+ context: { type: 'object', description: 'Session context (commits, changes, notes)' },
142
+ framework: { type: 'string', description: 'Storytelling framework override' },
143
+ output: { type: 'string', description: 'Relative output path' },
144
+ },
145
+ };
146
+ this.tools = STORY_TYPES.map((storyType) => ({
147
+ name: `write_${storyType}`,
148
+ description: `Prepare ${storyType} story brief using storyteller SKILL.md`,
149
+ inputSchema: writeSchema,
150
+ }));
151
+ this.handlers = {
152
+ write_reflection: async (args) => writeStoryTool('reflection', args),
153
+ write_saga: async (args) => writeStoryTool('saga', args),
154
+ write_journey: async (args) => writeStoryTool('journey', args),
155
+ write_narrative: async (args) => writeStoryTool('narrative', args),
156
+ };
157
+ this.setupToolHandlers();
158
+ }
159
+ }
160
+ if (import.meta.url === `file://${fileURLToPath(import.meta.url)}`) {
161
+ const server = new StorytellerServer();
162
+ server.run().catch((error) => {
163
+ process.stderr.write(`FATAL: ${String(error)}\n`);
164
+ process.exit(1);
165
+ });
166
+ }
167
+ export { StorytellerServer };
@@ -1,9 +1,12 @@
1
1
  /**
2
2
  * Agent Capabilities Configuration
3
3
  *
4
- * Centralized agent capability definitions for orchestration decisions
4
+ * Centralized agent capability definitions for orchestration decisions.
5
+ * Enriched at runtime by the active MemoryRoutingProvider (Repertoire, etc.).
5
6
  */
6
7
  import { AGENT_REGISTRY } from "../../../agents/registry.js";
8
+ import { initializeMemoryRouting } from '../../../memory-routing/index.js';
9
+ import { getProvider, toMemoryCapabilityMap, fromMemoryCapabilityMap, } from './memory-routing-bridge.js';
7
10
  const DEFAULT_AGENT_CAPABILITIES = Object.fromEntries(Object.entries(AGENT_REGISTRY).map(([name, entry]) => [
8
11
  name,
9
12
  {
@@ -12,17 +15,28 @@ const DEFAULT_AGENT_CAPABILITIES = Object.fromEntries(Object.entries(AGENT_REGIS
12
15
  concurrentTasks: entry.concurrentTasks,
13
16
  },
14
17
  ]));
18
+ initializeMemoryRouting();
15
19
  /**
16
20
  * Agent Capabilities Manager
17
21
  * Manages agent capabilities for orchestration decisions
18
22
  */
19
23
  export class AgentCapabilitiesManager {
20
24
  capabilities = new Map();
25
+ enriched = false;
21
26
  constructor() {
22
- // Initialize with default capabilities
23
27
  Object.entries(DEFAULT_AGENT_CAPABILITIES).forEach(([agent, config]) => {
24
28
  this.capabilities.set(agent, config);
25
29
  });
30
+ this.applyMemoryRoutingEnrichment();
31
+ }
32
+ applyMemoryRoutingEnrichment() {
33
+ const provider = getProvider();
34
+ if (provider.id === 'null')
35
+ return;
36
+ const memoryCaps = toMemoryCapabilityMap(this.capabilities);
37
+ const enriched = provider.enhanceAgentCapabilities(memoryCaps);
38
+ this.capabilities = fromMemoryCapabilityMap(enriched);
39
+ this.enriched = true;
26
40
  }
27
41
  /**
28
42
  * Get capabilities for a specific agent
@@ -34,6 +48,8 @@ export class AgentCapabilitiesManager {
34
48
  * Get all registered agent capabilities
35
49
  */
36
50
  getAllCapabilities() {
51
+ if (!this.enriched)
52
+ this.applyMemoryRoutingEnrichment();
37
53
  return new Map(this.capabilities);
38
54
  }
39
55
  /**
@@ -43,19 +59,20 @@ export class AgentCapabilitiesManager {
43
59
  this.capabilities.set(agentType, capability);
44
60
  }
45
61
  /**
46
- * Select the best agent for a task based on complexity and capabilities
62
+ * Select the best agent for a task based on complexity, capabilities, and memory routing.
47
63
  */
48
- selectAgentForTask(requiredCapabilities, complexity) {
64
+ selectAgentForTask(requiredCapabilities, complexity, operationDescription = '') {
65
+ const provider = getProvider();
66
+ if (provider.id !== 'null' && operationDescription) {
67
+ const memoryCaps = toMemoryCapabilityMap(this.getAllCapabilities());
68
+ return provider.selectAgent(memoryCaps, requiredCapabilities, complexity, operationDescription);
69
+ }
49
70
  let bestAgent = null;
50
71
  let bestScore = -1;
51
72
  for (const [agent, caps] of this.capabilities) {
52
- // Check if agent can handle the complexity
53
- if (complexity > caps.complexityThreshold) {
73
+ if (complexity > caps.complexityThreshold)
54
74
  continue;
55
- }
56
- // Calculate capability match score
57
- const matchCount = requiredCapabilities.filter(cap => caps.capabilities.includes(cap)).length;
58
- // Prefer agents with more concurrent tasks available
75
+ const matchCount = requiredCapabilities.filter((cap) => caps.capabilities.includes(cap)).length;
59
76
  const score = matchCount * 10 + caps.concurrentTasks;
60
77
  if (score > bestScore) {
61
78
  bestScore = score;
@@ -77,7 +94,6 @@ export class AgentCapabilitiesManager {
77
94
  return available;
78
95
  }
79
96
  }
80
- // Singleton instance
81
97
  let capabilitiesManagerInstance = null;
82
98
  export function getAgentCapabilitiesManager() {
83
99
  if (!capabilitiesManagerInstance) {
@@ -85,3 +101,6 @@ export function getAgentCapabilitiesManager() {
85
101
  }
86
102
  return capabilitiesManagerInstance;
87
103
  }
104
+ export function resetAgentCapabilitiesManager() {
105
+ capabilitiesManagerInstance = null;
106
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Bridge between orchestrator types and the pluggable MemoryRoutingProvider.
3
+ */
4
+ import { getMemoryRoutingProviderSync, } from '../../../memory-routing/index.js';
5
+ export function toMemoryCapability(caps) {
6
+ const result = {
7
+ capabilities: caps.capabilities,
8
+ complexityThreshold: caps.complexityThreshold,
9
+ concurrentTasks: caps.concurrentTasks,
10
+ };
11
+ if (caps.memorySignals)
12
+ result.memorySignals = caps.memorySignals;
13
+ if (caps.memoryTags)
14
+ result.memoryTags = caps.memoryTags;
15
+ return result;
16
+ }
17
+ export function fromMemoryCapability(caps) {
18
+ const result = {
19
+ capabilities: caps.capabilities,
20
+ complexityThreshold: caps.complexityThreshold,
21
+ concurrentTasks: caps.concurrentTasks,
22
+ };
23
+ if (caps.memorySignals)
24
+ result.memorySignals = caps.memorySignals;
25
+ if (caps.memoryTags)
26
+ result.memoryTags = caps.memoryTags;
27
+ return result;
28
+ }
29
+ export function toMemoryTask(task) {
30
+ const result = {
31
+ id: task.id,
32
+ description: task.description,
33
+ type: task.type,
34
+ };
35
+ if (task.priority)
36
+ result.priority = task.priority;
37
+ if (task.dependencies)
38
+ result.dependencies = task.dependencies;
39
+ if (task.estimatedComplexity !== undefined)
40
+ result.estimatedComplexity = task.estimatedComplexity;
41
+ if (task.metadata)
42
+ result.metadata = task.metadata;
43
+ return result;
44
+ }
45
+ export function fromMemoryTask(task) {
46
+ const result = {
47
+ id: task.id,
48
+ description: task.description,
49
+ type: task.type,
50
+ };
51
+ if (task.priority)
52
+ result.priority = task.priority;
53
+ if (task.dependencies)
54
+ result.dependencies = task.dependencies;
55
+ if (task.estimatedComplexity !== undefined)
56
+ result.estimatedComplexity = task.estimatedComplexity;
57
+ const metadata = task.metadata;
58
+ if (metadata)
59
+ result.metadata = metadata;
60
+ return result;
61
+ }
62
+ export function toMemoryCapabilityMap(caps) {
63
+ return new Map(Array.from(caps.entries()).map(([k, v]) => [k, toMemoryCapability(v)]));
64
+ }
65
+ export function fromMemoryCapabilityMap(caps) {
66
+ return new Map(Array.from(caps.entries()).map(([k, v]) => [k, fromMemoryCapability(v)]));
67
+ }
68
+ export function getProvider() {
69
+ return getMemoryRoutingProviderSync();
70
+ }
@@ -4,6 +4,7 @@
4
4
  * Creates optimized execution plans for orchestration tasks
5
5
  */
6
6
  import { getAgentCapabilitiesManager } from '../config/agent-capabilities.js';
7
+ import { getProvider, toMemoryTask, fromMemoryTask, } from '../config/memory-routing-bridge.js';
7
8
  /**
8
9
  * Execution Planner
9
10
  * Plans and optimizes task execution strategies
@@ -48,26 +49,35 @@ export class ExecutionPlanner {
48
49
  * Create an execution plan based on tasks and mode
49
50
  */
50
51
  async createExecutionPlan(tasks, executionMode) {
52
+ const provider = getProvider();
53
+ const memoryTasks = provider.enrichTasks(tasks.map(toMemoryTask));
54
+ const enrichedTasks = memoryTasks.map(fromMemoryTask);
51
55
  const agentAssignments = new Map();
52
56
  switch (executionMode) {
53
57
  case 'parallel':
54
- this.createParallelPlan(tasks, agentAssignments);
58
+ this.createParallelPlan(enrichedTasks, agentAssignments);
55
59
  break;
56
60
  case 'sequential':
57
- this.createSequentialPlan(tasks, agentAssignments);
61
+ this.createSequentialPlan(enrichedTasks, agentAssignments);
58
62
  break;
59
63
  case 'optimized':
60
64
  default:
61
- await this.createOptimizedPlan(tasks, agentAssignments);
65
+ await this.createOptimizedPlan(enrichedTasks, agentAssignments);
62
66
  break;
63
67
  }
64
68
  const estimatedDuration = this.estimateExecutionDuration(agentAssignments);
65
- return {
66
- tasks,
69
+ const plan = {
70
+ tasks: enrichedTasks,
67
71
  strategy: executionMode,
68
72
  agentAssignments,
69
73
  estimatedDuration,
70
74
  };
75
+ if (provider.id !== 'null') {
76
+ plan.memoryContext = {
77
+ ...provider.buildInheritedContext(memoryTasks),
78
+ };
79
+ }
80
+ return plan;
71
81
  }
72
82
  /**
73
83
  * Create a parallel execution plan
@@ -149,8 +159,15 @@ export class ExecutionPlanner {
149
159
  */
150
160
  assignTasksToAgents(tasks, agentAssignments) {
151
161
  for (const task of tasks) {
152
- const complexity = task.estimatedComplexity || 30;
153
- const agent = this.capabilitiesManager.selectAgentForTask([task.type], complexity) || 'orchestrator';
162
+ const complexity = this.calculateTaskComplexity(task);
163
+ const requiredCaps = [
164
+ task.type,
165
+ ...(task.metadata?.memorySignals ?? []),
166
+ ];
167
+ const operationDescription = task.metadata?.memoryHighConfidenceTrap
168
+ ? `${task.description} TYPE: ontological-trap`
169
+ : task.description;
170
+ const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, operationDescription) || 'orchestrator';
154
171
  if (!agentAssignments.has(agent)) {
155
172
  agentAssignments.set(agent, []);
156
173
  }
@@ -188,7 +205,11 @@ export class ExecutionPlanner {
188
205
  category: task.type,
189
206
  });
190
207
  // Assign to agent
191
- const agent = this.capabilitiesManager.selectAgentForTask([task.type], complexity) || 'orchestrator';
208
+ const requiredCaps = [
209
+ task.type,
210
+ ...(task.metadata?.memorySignals ?? []),
211
+ ];
212
+ const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, task.description) || 'orchestrator';
192
213
  if (!assignments.has(agent)) {
193
214
  assignments.set(agent, []);
194
215
  }
@@ -246,6 +267,15 @@ export class ExecutionPlanner {
246
267
  if (task.dependencies) {
247
268
  complexity += task.dependencies.length * 5;
248
269
  }
270
+ if (task.metadata?.memoryComplexityBoost !== undefined) {
271
+ complexity += task.metadata.memoryComplexityBoost;
272
+ }
273
+ else {
274
+ const provider = getProvider();
275
+ if (provider.id !== 'null' && provider.getTaskConfidence) {
276
+ complexity += provider.getTaskConfidence(toMemoryTask(task)).complexityBoost;
277
+ }
278
+ }
249
279
  return Math.min(Math.max(Math.round(complexity), 1), 100);
250
280
  }
251
281
  /**
@@ -6,7 +6,8 @@
6
6
  import { frameworkLogger } from '../../../core/framework-logger.js';
7
7
  import { getExecutionPlanner } from '../execution/execution-planner.js';
8
8
  import { mcpClientManager } from '../../../mcps/mcp-client.js';
9
- import { addObservations, extractOrchestrationObservations } from '../aside-context.js';
9
+ import { addObservations, extractOrchestrationObservations, spawnAside } from '../aside-context.js';
10
+ import { getProvider } from '../config/memory-routing-bridge.js';
10
11
  /**
11
12
  * Task Handler
12
13
  * Processes orchestrate-task requests
@@ -38,8 +39,37 @@ export class TaskHandler {
38
39
  }
39
40
  // Analyze complexity and create execution plan
40
41
  const executionPlan = await this.planner.createExecutionPlan(tasks, executionMode);
42
+ const memoryProvider = getProvider();
43
+ if (memoryProvider.id !== 'null' && executionPlan.memoryContext) {
44
+ await spawnAside({
45
+ description: `Orchestrate: ${description}`,
46
+ sessionId,
47
+ inheritedContext: {
48
+ memoryRouting: executionPlan.memoryContext,
49
+ },
50
+ });
51
+ }
41
52
  // Execute orchestration (simulated for MCP server)
42
53
  const results = await this.executePlan(executionPlan, sessionId, timeout);
54
+ // Feed per-task outcomes back to memory provider (not aggregate session stats)
55
+ if (memoryProvider.ingestFeedback) {
56
+ const outcomeByKey = new Map(results.taskOutcomes.map((o) => [`${o.agent}:${o.taskId}`, o]));
57
+ for (const [agent, assignedTasks] of executionPlan.agentAssignments) {
58
+ for (const task of assignedTasks) {
59
+ const outcome = outcomeByKey.get(`${agent}:${task.id}`);
60
+ memoryProvider.ingestFeedback({
61
+ timestamp: new Date().toISOString(),
62
+ sessionId,
63
+ taskId: task.id,
64
+ assignedAgent: agent,
65
+ memorySignals: task.metadata?.memorySignals ?? [],
66
+ complexity: task.estimatedComplexity ?? 30,
67
+ success: outcome?.success ?? false,
68
+ durationMs: outcome?.durationMs ?? 0,
69
+ });
70
+ }
71
+ }
72
+ }
43
73
  // Update result
44
74
  orchestrationResult.success = results.success;
45
75
  orchestrationResult.completedTasks = results.completedTasks;
@@ -82,6 +112,7 @@ export class TaskHandler {
82
112
  let completedTasks = 0;
83
113
  let failedTasks = 0;
84
114
  const agentOutputs = {};
115
+ const taskOutcomes = [];
85
116
  const skillServers = new Set([
86
117
  'code-review', 'code-reviewer',
87
118
  'security-audit', 'security-auditor',
@@ -96,6 +127,7 @@ export class TaskHandler {
96
127
  agentUtilization[agent] = tasks.length;
97
128
  if (skillServers.has(agent)) {
98
129
  for (const task of tasks) {
130
+ const taskStart = Date.now();
99
131
  try {
100
132
  const toolName = this.mapAgentToTool(agent);
101
133
  const result = await mcpClientManager.callServerTool(agent, toolName, {
@@ -106,10 +138,22 @@ export class TaskHandler {
106
138
  const outputText = this.extractTextFromMcpResult(result);
107
139
  agentOutputs[`${agent}:${task.id}`] = outputText;
108
140
  completedTasks++;
141
+ taskOutcomes.push({
142
+ taskId: task.id,
143
+ agent,
144
+ success: true,
145
+ durationMs: Date.now() - taskStart,
146
+ });
109
147
  }
110
148
  catch (err) {
111
149
  failedTasks++;
112
150
  agentOutputs[`${agent}:${task.id}`] = `Error: ${err instanceof Error ? err.message : String(err)}`;
151
+ taskOutcomes.push({
152
+ taskId: task.id,
153
+ agent,
154
+ success: false,
155
+ durationMs: Date.now() - taskStart,
156
+ });
113
157
  frameworkLogger.log('orchestrator.task-handler', 'task-execution-failed', 'warning', {
114
158
  agent,
115
159
  taskId: task.id,
@@ -120,7 +164,15 @@ export class TaskHandler {
120
164
  }
121
165
  else {
122
166
  // For non-MCP agents we still count them as "assigned" (they will be handled by the caller or legacy path)
123
- completedTasks += tasks.length;
167
+ for (const task of tasks) {
168
+ completedTasks++;
169
+ taskOutcomes.push({
170
+ taskId: task.id,
171
+ agent,
172
+ success: true,
173
+ durationMs: 0,
174
+ });
175
+ }
124
176
  }
125
177
  }
126
178
  const recommendations = [];
@@ -141,6 +193,7 @@ export class TaskHandler {
141
193
  bottlenecks,
142
194
  recommendations,
143
195
  agentOutputs,
196
+ taskOutcomes,
144
197
  };
145
198
  }
146
199
  mapAgentToTool(agent) {