mio-agent-runtime 0.5.15 → 0.5.16

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.
@@ -5,7 +5,10 @@ const fs = require('fs')
5
5
  const path = require('path')
6
6
  const crypto = require('crypto')
7
7
  const readline = require('readline')
8
- const { execFileSync } = require('child_process')
8
+ const { execFileSync } = require('child_process')
9
+ const { getEvolutionStatus } = require('../runtime-modules.js')
10
+ const { listHostCapabilities } = require('../host-capabilities.js')
11
+ const { createEvolutionCutoverTools } = require('../evolution-cutover.js')
9
12
 
10
13
  const SERVER_INFO = { name: 'mio-intelligence-mcp', version: '0.1.0' }
11
14
  const PROTOCOL_VERSION = '2024-11-05'
@@ -20,11 +23,10 @@ const queryPath = path.join(dataDir, 'queries.jsonl')
20
23
  const agentsPath = path.join(dataDir, 'agents.jsonl')
21
24
  const subscriptionPath = path.join(dataDir, 'subscriptions.jsonl')
22
25
  const digestStatePath = path.join(dataDir, 'digest_state.json')
23
- const ideasPath = path.join(dataDir, 'ideas.jsonl')
24
- const suggestionsPath = path.join(dataDir, 'suggestions.jsonl')
25
- fs.mkdirSync(dataDir, { recursive: true })
26
-
27
- const { loadPhase0, summarizePhase0, renderPhase0Markdown } = require('./phase0')
26
+ fs.mkdirSync(dataDir, { recursive: true })
27
+
28
+ const { loadPhase0, summarizePhase0, renderPhase0Markdown } = require('./phase0')
29
+ const evolutionCutover = createEvolutionCutoverTools({ dataDir, appendJsonl, readJsonl, projectName })
28
30
 
29
31
  let runtimeContext = {}
30
32
  try {
@@ -1594,209 +1596,132 @@ const TOOLS = [
1594
1596
  },
1595
1597
  },
1596
1598
  },
1597
- {
1598
- name: 'mio.evolution.report',
1599
- description: 'Generate cross-agent evolution report: ecosystem summary, agent performance comparison, cross-agent patterns, memory health, and optimization suggestions (ADR-017 Evolution plane).',
1599
+ {
1600
+ name: 'mio.evolution.report',
1601
+ description: 'Generate cross-agent evolution report: ecosystem summary, agent performance comparison, cross-agent patterns, memory health, and optimization suggestions (ADR-017 Evolution plane).',
1600
1602
  inputSchema: {
1601
1603
  type: 'object',
1602
1604
  properties: {
1603
1605
  project: { type: 'string', description: 'Project name filter. Defaults to current repository.' },
1604
1606
  period: { type: 'string', description: 'Time window: 24h, 7d, 30d, or all (default).' },
1605
1607
  },
1606
- },
1607
- },
1608
- {
1609
- name: 'mio.task.record_outcome',
1610
- description: 'Record task outcome with agent registry update and auto-claim experience reuse in one atomic call. Combines observer.ingest + agent stats + auto-claim for a complete task lifecycle closure.',
1611
- inputSchema: {
1612
- type: 'object',
1613
- properties: {
1614
- outcome: { type: 'string', description: 'Task outcome: success, failure, or aborted.' },
1615
- task: { type: 'string', description: 'Brief task description.' },
1616
- summary: { type: 'string', description: 'Optional task summary.' },
1617
- verification: { type: 'string', description: 'Optional verification details.' },
1618
- agentId: { type: 'string', description: 'Agent identifier. Defaults to MIO_CONTEXT agentId.' },
1619
- project: { type: 'string', description: 'Project name. Defaults to current repository.' },
1620
- traceId: { type: 'string', description: 'Optional custom trace ID. Auto-generated if omitted.' },
1621
- },
1622
- required: ['outcome'],
1623
- },
1608
+ },
1624
1609
  },
1625
1610
  {
1626
- name: 'mio.idea.generate',
1627
- description: 'Generate creative ideas or multiple candidate solutions based on a given goal, context, and constraints.',
1611
+ name: 'mio.evolution.status',
1612
+ description: 'Report composed mio-agent-runtime module health from the canonical runtime module registry.',
1613
+ inputSchema: {
1614
+ type: 'object',
1615
+ properties: {},
1616
+ },
1617
+ },
1618
+ {
1619
+ name: 'mio.host.capabilities',
1620
+ description: 'List installed desktop host adapters and the safe capability surface they expose to runtime modules.',
1621
+ inputSchema: {
1622
+ type: 'object',
1623
+ properties: {},
1624
+ },
1625
+ },
1626
+ {
1627
+ name: 'mio.evolution.shadow.record',
1628
+ description: 'Record a shadow comparison between legacy and modular runtime outputs without changing authority.',
1628
1629
  inputSchema: {
1629
1630
  type: 'object',
1630
- required: ['goal'],
1631
1631
  properties: {
1632
- goal: { type: 'string', description: 'The goal or problem description for which to generate ideas.' },
1633
- context: { type: 'string', description: '(Optional) Additional background information, such as prior decisions or known problems.' },
1634
- constraints: { type: 'array', items: { type: 'string' }, description: '(Optional) List of constraints, e.g. "no new dependencies", "must be implementable as a plugin".' },
1635
- numIdeas: { type: 'integer', description: '(Optional) Number of ideas to return, default 3.', default: 3, minimum: 1 }
1632
+ label: { type: 'string', description: 'Human-readable comparison label.' },
1633
+ project: { type: 'string', description: 'Project name. Defaults to current repository.' },
1634
+ legacy: { type: 'object', description: 'Legacy path output snapshot.' },
1635
+ modular: { type: 'object', description: 'Modular path output snapshot.' },
1636
+ input: { type: 'object', description: 'Optional sanitized input snapshot.' },
1636
1637
  },
1637
- additionalProperties: false
1638
+ required: ['legacy', 'modular'],
1638
1639
  },
1639
1640
  },
1640
1641
  {
1641
- name: 'mio.idea.list',
1642
- description: 'List previously generated ideas, optionally filtered by keyword, strategy, or time window.',
1642
+ name: 'mio.evolution.dual_write.record',
1643
+ description: 'Record a dual-write sample result for legacy and modular state paths without switching authority.',
1643
1644
  inputSchema: {
1644
1645
  type: 'object',
1645
1646
  properties: {
1646
- goal: { type: 'string', description: '(Optional) Filter ideas whose goal contains this keyword.' },
1647
- strategy: { type: 'string', description: '(Optional) Filter by generation strategy (e.g. SCAMPER, Analogy).' },
1648
- limit: { type: 'integer', description: '(Optional) Max results, default 10.', default: 10, minimum: 1 },
1649
- period: { type: 'string', description: '(Optional) Time window: 24h, 7d, 30d, or all (default).' }
1650
- }
1647
+ label: { type: 'string', description: 'Human-readable dual-write label.' },
1648
+ project: { type: 'string', description: 'Project name. Defaults to current repository.' },
1649
+ authoritative: { type: 'string', description: 'Authoritative path: legacy or modular. Defaults to legacy.' },
1650
+ legacyResult: { type: 'object', description: 'Legacy write result snapshot.' },
1651
+ modularResult: { type: 'object', description: 'Modular write result snapshot.' },
1652
+ record: { type: 'object', description: 'Optional sanitized record metadata.' },
1653
+ },
1654
+ required: ['legacyResult', 'modularResult'],
1651
1655
  },
1652
1656
  },
1653
1657
  {
1654
- name: 'mio.evolution.suggest',
1655
- description: 'Analyze ecosystem data and produce prioritized improvement suggestions with next actions and expected impact.',
1658
+ name: 'mio.evolution.cutover.readiness',
1659
+ description: 'Assess whether shadow and dual-write samples are sufficient to consider modular runtime cutover.',
1656
1660
  inputSchema: {
1657
1661
  type: 'object',
1658
1662
  properties: {
1659
- project: { type: 'string', description: 'Project name filter. Defaults to current repository.' }
1660
- }
1663
+ project: { type: 'string', description: 'Project name. Defaults to current repository.' },
1664
+ minShadowRuns: { type: 'number', description: 'Minimum shadow comparison samples required. Defaults to 5.' },
1665
+ maxMismatchRate: { type: 'number', description: 'Allowed shadow mismatch rate. Defaults to 0.' },
1666
+ },
1661
1667
  },
1662
1668
  },
1663
- ,
1664
1669
  {
1665
- name: 'mio.dashboard.start',
1666
- description: 'Start the Mio live dashboard HTTP server and return its URL. Aggregates MIO_HOME data into a browser-viewable dashboard.',
1670
+ name: 'mio.evolution.migration.plan',
1671
+ description: 'Preview a state migration plan between legacy and modular records without writing state.',
1667
1672
  inputSchema: {
1668
1673
  type: 'object',
1669
1674
  properties: {
1670
- port: { type: 'integer', description: '(Optional) Port to bind, default 8787.', default: 8787, minimum: 1 },
1671
- open: { type: 'boolean', description: '(Optional) Open the dashboard in the default browser after starting.' }
1672
- }
1675
+ legacyRecords: { type: 'array', items: { type: 'object' }, description: 'Legacy state records.' },
1676
+ modularRecords: { type: 'array', items: { type: 'object' }, description: 'Existing modular state records.' },
1677
+ },
1673
1678
  },
1674
1679
  },
1675
1680
  {
1676
- name: 'mio.dashboard.stop',
1677
- description: 'Stop the running Mio dashboard HTTP server.',
1678
- inputSchema: { type: 'object', properties: {} },
1681
+ name: 'mio.evolution.authority.plan',
1682
+ description: 'Create a gated authority switch plan from legacy to modular runtime without applying it.',
1683
+ inputSchema: {
1684
+ type: 'object',
1685
+ properties: {
1686
+ readiness: { type: 'object', description: 'Result from mio.evolution.cutover.readiness.' },
1687
+ from: { type: 'string', description: 'Current authoritative path. Defaults to legacy.' },
1688
+ to: { type: 'string', description: 'Target authoritative path. Defaults to modular.' },
1689
+ },
1690
+ required: ['readiness'],
1691
+ },
1679
1692
  },
1680
1693
  {
1681
- name: 'mio.dashboard.status',
1682
- description: 'Check if the Mio dashboard HTTP server is running.',
1683
- inputSchema: { type: 'object', properties: {} },
1684
- }]
1685
-
1686
- function handleIdeaGenerate(args = {}) {
1687
- const goal = String(args.goal || '').trim()
1688
- if (!goal) throw new Error('idea.generate requires a goal')
1689
- const numIdeas = Math.min(Math.max(Number(args.numIdeas) || 3, 1), 10)
1690
- const context = args.context ? String(args.context).trim() : ''
1691
- const constraints = Array.isArray(args.constraints) ? args.constraints.map(String) : []
1692
-
1693
- // Query Mio memory for related context
1694
- const relatedRecords = readJsonl(memoryPath)
1695
- .filter(r => r.archived !== true)
1696
- .filter(r => {
1697
- const text = (r.content || '').toLowerCase()
1698
- const goalLower = goal.toLowerCase()
1699
- // Support both space-separated (English) and continuous (Chinese) matching
1700
- const goalWords = goalLower.split(/\s+/).filter(w => w.length > 2)
1701
- // For Chinese: extract 2-char n-grams as search tokens
1702
- const ngrams = []
1703
- for (let i = 0; i < goalLower.length - 1; i++) {
1704
- const ng = goalLower.slice(i, i + 2)
1705
- if (ng.trim().length === 2) ngrams.push(ng)
1706
- }
1707
- const allTokens = [...new Set([...goalWords, ...ngrams])]
1708
- return allTokens.some(t => text.includes(t))
1709
- })
1710
- .slice(0, 8)
1711
-
1712
- const relatedMemoryText = relatedRecords.length > 0
1713
- ? relatedRecords.map(r => '- [' + r.kind + '] ' + (r.content || '').slice(0, 200)).join('\n')
1714
- : '(no related memories found)'
1715
-
1716
- const strategies = [
1717
- {
1718
- name: 'SCAMPER',
1719
- prompt: 'Apply SCAMPER: Substitute, Combine, Adapt, Modify, Put to another use, Eliminate, Reverse. ' +
1720
- 'For goal: ' + goal + '. What novel combination or modification of existing elements could work?'
1721
- },
1722
- {
1723
- name: 'Analogy',
1724
- prompt: 'By analogy: What similar problem has been solved in a completely different domain? ' +
1725
- 'For goal: ' + goal + '. What approach from another field (biology, economics, gaming, logistics) transfers here?'
1726
- },
1727
- {
1728
- name: 'First-Principles',
1729
- prompt: 'First principles: Strip away all assumptions. What are the absolute basics of ' + goal + '? ' +
1730
- 'What would you build if you had no prior art, no constraints, no legacy?'
1731
- },
1732
- {
1733
- name: 'Random-Stimulus',
1734
- prompt: 'Random stimulus: Pick an unrelated concept (a relay race, a restaurant menu, a river delta, a beehive). ' +
1735
- 'How does it relate to ' + goal + '? What structural or procedural parallel exists?'
1736
- },
1737
- {
1738
- name: 'Constraint-Inversion',
1739
- prompt: 'Constraint inversion: Instead of ' + goal + ', what is the OPPOSITE goal? ' +
1740
- 'How would you deliberately make things worse? Now invert the inversion — what does that reveal about the real solution?'
1741
- }
1742
- ]
1743
-
1744
- const selectedStrategies = strategies.slice(0, numIdeas)
1745
- const ideas = []
1746
-
1747
- for (let i = 0; i < selectedStrategies.length; i++) {
1748
- const s = selectedStrategies[i]
1749
- const idea = {
1750
- id: createId('idea'),
1751
- title: 'Idea #' + (i + 1) + ' (' + s.name + '): ' + goal,
1752
- description: 'Goal: ' + goal + '\n\n' +
1753
- 'Strategy: ' + s.name + '\n\n' +
1754
- 'Related Mio memory:\n' + relatedMemoryText + '\n\n' +
1755
- (context ? 'Context: ' + context + '\n\n' : '') +
1756
- (constraints.length > 0 ? 'Constraints:\n' + constraints.map(c => '- ' + c).join('\n') + '\n\n' : '') +
1757
- 'Strategy prompt: ' + s.prompt + '\n\n' +
1758
- 'Suggestion: Consider prototyping the idea and measuring its impact against prior decisions.',
1759
- provenance: {
1760
- strategy: s.name,
1761
- relatedMemoryIds: relatedRecords.map(r => r.id).slice(0, 5),
1694
+ name: 'mio.evolution.cutover.apply',
1695
+ description: 'Dry-run an authority switch plan. This stage refuses real cutover and never mutates authority state.',
1696
+ inputSchema: {
1697
+ type: 'object',
1698
+ properties: {
1699
+ dryRun: { type: 'boolean', description: 'Must be true. Real cutover is intentionally gated.' },
1700
+ project: { type: 'string', description: 'Project name. Defaults to current repository.' },
1701
+ plan: { type: 'object', description: 'Authority switch plan from mio.evolution.authority.plan.' },
1762
1702
  },
1763
- generatedAt: new Date().toISOString(),
1764
- goal,
1765
- context: context || null,
1766
- constraints,
1767
- }
1768
- ideas.push(idea)
1769
- }
1770
-
1771
- // Persist to ideas.jsonl
1772
- for (const idea of ideas) {
1773
- appendJsonl(ideasPath, idea)
1774
- }
1775
-
1776
- return { ideas, count: ideas.length, goal, strategies: ideas.map(i => i.provenance.strategy) }
1777
- }
1778
-
1779
- function listIdeas(args = {}) {
1780
- if (!fs.existsSync(ideasPath)) return { ideas: [], count: 0, total: 0 }
1781
- const now = Date.now()
1782
- const period = String(args.period || 'all').trim()
1783
- const periodMs = period === '24h' ? 86400000 : period === '7d' ? 604800000 : period === '30d' ? 2592000000 : Infinity
1784
- const cutoff = periodMs === Infinity ? 0 : now - periodMs
1785
- const goalFilter = args.goal ? String(args.goal).toLowerCase() : null
1786
- const strategyFilter = args.strategy ? String(args.strategy).trim().toLowerCase() : null
1787
- const limit = Math.min(Math.max(Number(args.limit) || 10, 1), 50)
1788
- const all = fs.readFileSync(ideasPath, 'utf8').split('\n').filter(Boolean).map(line => {
1789
- try { return JSON.parse(line) } catch (_) { return null }
1790
- }).filter(Boolean)
1791
- const filtered = all.filter(idea => {
1792
- if (cutoff && new Date(idea.generatedAt).getTime() < cutoff) return false
1793
- if (goalFilter && !String(idea.goal || '').toLowerCase().includes(goalFilter)) return false
1794
- if (strategyFilter && String(idea.provenance?.strategy || '').toLowerCase() !== strategyFilter) return false
1795
- return true
1796
- })
1797
- return { ideas: filtered.slice(-limit), count: filtered.length, total: all.length }
1798
- }
1799
-
1703
+ required: ['dryRun', 'plan'],
1704
+ },
1705
+ },
1706
+ {
1707
+ name: 'mio.task.record_outcome',
1708
+ description: 'Record task outcome with agent registry update and auto-claim experience reuse in one atomic call. Combines observer.ingest + agent stats + auto-claim for a complete task lifecycle closure.',
1709
+ inputSchema: {
1710
+ type: 'object',
1711
+ properties: {
1712
+ outcome: { type: 'string', description: 'Task outcome: success, failure, or aborted.' },
1713
+ task: { type: 'string', description: 'Brief task description.' },
1714
+ summary: { type: 'string', description: 'Optional task summary.' },
1715
+ verification: { type: 'string', description: 'Optional verification details.' },
1716
+ agentId: { type: 'string', description: 'Agent identifier. Defaults to MIO_CONTEXT agentId.' },
1717
+ project: { type: 'string', description: 'Project name. Defaults to current repository.' },
1718
+ traceId: { type: 'string', description: 'Optional custom trace ID. Auto-generated if omitted.' },
1719
+ },
1720
+ required: ['outcome'],
1721
+ },
1722
+ },
1723
+ ]
1724
+
1800
1725
  async function callTool(name, args = {}) {
1801
1726
  switch (name) {
1802
1727
  case 'mio.memory.query':
@@ -1833,77 +1758,31 @@ async function callTool(name, args = {}) {
1833
1758
  return listAgents(args)
1834
1759
  case 'mio.agent.report':
1835
1760
  return reportAgent(args)
1836
- case 'mio.evolution.report':
1837
- return evolutionReport(args)
1761
+ case 'mio.evolution.report':
1762
+ return evolutionReport(args)
1763
+ case 'mio.evolution.status':
1764
+ return getEvolutionStatus()
1765
+ case 'mio.host.capabilities':
1766
+ return listHostCapabilities()
1767
+ case 'mio.evolution.shadow.record':
1768
+ return evolutionCutover.recordShadowComparison(args)
1769
+ case 'mio.evolution.dual_write.record':
1770
+ return evolutionCutover.recordDualWrite(args)
1771
+ case 'mio.evolution.cutover.readiness':
1772
+ return evolutionCutover.cutoverReadiness(args)
1773
+ case 'mio.evolution.migration.plan':
1774
+ return evolutionCutover.migrationPlan(args)
1775
+ case 'mio.evolution.authority.plan':
1776
+ return evolutionCutover.authorityPlan(args)
1777
+ case 'mio.evolution.cutover.apply':
1778
+ return evolutionCutover.applyCutover(args)
1838
1779
  case 'mio.task.record_outcome':
1839
1780
  return recordTaskOutcome(args)
1840
- case 'mio.idea.generate':
1841
- return handleIdeaGenerate(args)
1842
- case 'mio.idea.list':
1843
- return listIdeas(args)
1844
- case 'mio.evolution.suggest':
1845
- return evolutionSuggest(args)
1846
- case 'mio.dashboard.start':
1847
- return handleDashboardStart(args)
1848
- case 'mio.dashboard.stop':
1849
- return handleDashboardStop()
1850
- case 'mio.dashboard.status':
1851
- return handleDashboardStatus()
1852
1781
  default:
1853
1782
  throw new Error(`Unknown tool: ${name}`)
1854
1783
  }
1855
1784
  }
1856
1785
 
1857
- const DASHBOARD_PORT = 8787
1858
- const dashboardPidPath = () => path.join(dataDir, 'dashboard.pid')
1859
-
1860
- function isDashboardRunning() {
1861
- const pidFile = dashboardPidPath()
1862
- if (!fs.existsSync(pidFile)) return false
1863
- try {
1864
- const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10)
1865
- process.kill(pid, 0)
1866
- return true
1867
- } catch (_) {
1868
- return false
1869
- }
1870
- }
1871
-
1872
- function handleDashboardStart(args = {}) {
1873
- const port = parseInt(args.port || process.env.MIO_DASHBOARD_PORT || DASHBOARD_PORT, 10)
1874
- const url = 'http://localhost:' + port
1875
- if (isDashboardRunning()) {
1876
- if (args.open) { try { require('child_process').exec('start ' + url) } catch (_) {} }
1877
- return { url: url, running: true, message: 'Dashboard already running at ' + url }
1878
- }
1879
- const serverScript = path.join(__dirname, 'dashboard-server.js')
1880
- const child = require('child_process').spawn(process.execPath, [serverScript, String(port)], {
1881
- env: Object.assign({}, process.env, { MIO_DATA_DIR: dataDir }),
1882
- detached: true,
1883
- stdio: 'ignore',
1884
- })
1885
- child.unref()
1886
- fs.writeFileSync(dashboardPidPath(), String(child.pid))
1887
- if (args.open) { try { require('child_process').exec('start ' + url) } catch (_) {} }
1888
- return { url: url, running: true, pid: child.pid, message: 'Dashboard started at ' + url }
1889
- }
1890
-
1891
- function handleDashboardStop() {
1892
- const pidFile = dashboardPidPath()
1893
- if (!fs.existsSync(pidFile)) return { running: false, message: 'Dashboard not running.' }
1894
- try {
1895
- const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10)
1896
- process.kill(pid, 'SIGTERM')
1897
- } catch (_) {}
1898
- try { fs.unlinkSync(pidFile) } catch (_) {}
1899
- return { running: false, message: 'Dashboard stopped.' }
1900
- }
1901
-
1902
- function handleDashboardStatus() {
1903
- const running = isDashboardRunning()
1904
- return { running: running, url: running ? 'http://localhost:' + DASHBOARD_PORT : null }
1905
- }
1906
-
1907
1786
  function jsonRpcResult(id, result) {
1908
1787
  return { jsonrpc: '2.0', id, result }
1909
1788
  }
@@ -2218,65 +2097,4 @@ function recordTaskOutcome(args = {}) {
2218
2097
  }
2219
2098
  }
2220
2099
 
2221
-
2222
- function evolutionSuggest(args = {}) {
2223
- const project = args.project || projectName()
2224
- const now = Date.now()
2225
- const memories = readJsonl(memoryPath)
2226
- const traces = readJsonl(tracePath)
2227
- const reuses = readJsonl(experienceReusePath)
2228
- const ideas = fs.existsSync(ideasPath)
2229
- ? fs.readFileSync(ideasPath, 'utf8').split('\n').filter(Boolean).map(l => { try { return JSON.parse(l) } catch (_) { return null } }).filter(Boolean)
2230
- : []
2231
- const agentIds = new Set()
2232
- traces.forEach((t) => { if (t.agent) agentIds.add(t.agent) })
2233
- const outcomes = traces.filter((t) => t.event_type === 'task_outcome')
2234
- const successes = outcomes.filter((t) => t.outcome === 'success').length
2235
- const successRate = outcomes.length > 0 ? Math.round((successes / outcomes.length) * 100) : 0
2236
- const verifiedReuses = reuses.filter((r) => r.confirmed && r.reuse && r.behaviorChanged && r.outcomeImproved)
2237
- const pendingReuses = reuses.filter((r) => r.source === 'auto_claim' && !r.confirmed)
2238
- const decisions = memories.filter((m) => m.kind === 'decision')
2239
- const problems = memories.filter((m) => m.kind === 'problem')
2240
- const shortMemories = memories.filter((m) => String(m.content || '').trim().length < 20)
2241
- const ideasWithoutMemory = ideas.filter((i) => !i.provenance?.relatedMemoryIds?.length)
2242
- const suggestions = []
2243
-
2244
- if (agentIds.size >= 2) {
2245
- const agentStats = []
2246
- for (const id of agentIds) {
2247
- const ao = outcomes.filter((t) => t.agent === id)
2248
- const as = ao.filter((t) => t.outcome === 'success').length
2249
- agentStats.push({ id, total: ao.length, success: as, rate: ao.length > 0 ? Math.round(as / ao.length * 100) : 0 })
2250
- }
2251
- agentStats.sort((a, b) => b.rate - a.rate)
2252
- const best = agentStats[0], worst = agentStats[agentStats.length - 1]
2253
- if (best.total >= 5 && worst.total >= 5 && best.rate - worst.rate >= 15) {
2254
- suggestions.push({ category: 'routing', priority: 'high', title: 'Route tasks to ' + best.id, description: best.id + ' has ' + best.rate + '% success rate vs ' + worst.id + ' at ' + worst.rate + '%.', nextAction: 'Update task routing rules to prefer ' + best.id, impact: 'Could improve overall success rate by ~' + Math.round((best.rate - worst.rate) * 0.3) + '%', basedOn: 'task_outcome comparison' })
2255
- }
2256
- }
2257
- if (shortMemories.length > 5 && memories.length > 10) {
2258
- suggestions.push({ category: 'memory', priority: 'medium', title: 'Enrich ' + shortMemories.length + ' short memory records', description: Math.round(shortMemories.length / memories.length * 100) + '% of memories have content < 20 chars.', nextAction: 'Review and expand short memory records, or archive irrelevant ones.', impact: 'Improves memory.query recall precision', basedOn: 'memory.jsonl analysis' })
2259
- }
2260
- if (pendingReuses.length >= 5) {
2261
- suggestions.push({ category: 'evidence', priority: 'medium', title: 'Confirm ' + pendingReuses.length + ' pending auto-claims', description: pendingReuses.length + ' auto-claimed reuses await confirmation.', nextAction: 'Call mio.experience.confirm on each auto_claim id.', impact: 'Increases verified reuse count toward Phase 0 threshold', basedOn: 'experience_reuse.jsonl' })
2262
- }
2263
- const crossAgent = verifiedReuses.filter((r) => r.sourceAgent !== r.targetAgent)
2264
- if (agentIds.size >= 2 && crossAgent.length === 0) {
2265
- suggestions.push({ category: 'interop', priority: 'high', title: 'Enable cross-agent experience sharing', description: 'Multiple agents exist but no cross-agent reuse detected.', nextAction: 'Ensure all agents query shared memory before designing solutions.', impact: 'Unlocks core Agent Control Plane value', basedOn: 'experience_reuse.jsonl' })
2266
- }
2267
- if (ideas.length > 0 && ideasWithoutMemory.length > ideas.length * 0.5) {
2268
- suggestions.push({ category: 'creativity', priority: 'low', title: 'Improve idea grounding (' + ideasWithoutMemory.length + ' ungrounded)', description: Math.round(ideasWithoutMemory.length / ideas.length * 100) + '% of ideas lack related memory context.', nextAction: 'Record more decision/problem memories to enrich the idea pipeline.', impact: 'Higher-quality, more context-aware ideas', basedOn: 'ideas.jsonl provenance' })
2269
- }
2270
- if (problems.length >= 3) {
2271
- const recent = problems.filter((p) => (now - new Date(p.timestamp).getTime()) < 7 * 86400000)
2272
- if (recent.length >= 2) {
2273
- suggestions.push({ category: 'health', priority: 'high', title: recent.length + ' problems in last 7 days', description: 'Recurring problems may indicate systemic issues.', nextAction: 'Review recent problems, identify root causes, create decision records.', impact: 'Prevents problem accumulation', basedOn: 'memory.jsonl recent problems' })
2274
- }
2275
- }
2276
- suggestions.sort((a, b) => ({ high: 0, medium: 1, low: 2 }[a.priority] || 2) - ({ high: 0, medium: 1, low: 2 }[b.priority] || 2))
2277
- const record = { id: 'evo_' + Date.now(), timestamp: new Date().toISOString(), project, metrics: { agents: agentIds.size, tasks: outcomes.length, successRate, memories: memories.length, decisions: decisions.length, problems: problems.length, verifiedReuses: verifiedReuses.length, pendingReuses: pendingReuses.length, ideas: ideas.length }, suggestions }
2278
- try { fs.appendFileSync(suggestionsPath, JSON.stringify(record) + '\n') } catch (_) {}
2279
- return record
2280
- }
2281
-
2282
2100
  module.exports = { TOOLS, callTool, handleMessage, readJsonl, appendJsonl, rl }
@@ -1,18 +1,18 @@
1
- {
2
- "name": "@mio/mio-intelligence-mcp",
3
- "version": "0.1.0",
4
- "private": true,
5
- "description": "Mio Agent Enhancement Layer - MCP-first intelligence core",
6
- "type": "commonjs",
7
- "main": "index.js",
8
- "bin": {
9
- "mio-intelligence-mcp": "index.js"
10
- },
11
- "scripts": {
12
- "start": "node index.js",
13
- "check": "node --check index.js"
14
- },
15
- "engines": {
16
- "node": ">=18"
17
- }
1
+ {
2
+ "name": "@akemi-mio/mio-intelligence-mcp",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Mio Agent Enhancement Layer - MCP-first intelligence core",
6
+ "type": "commonjs",
7
+ "main": "index.js",
8
+ "bin": {
9
+ "mio-intelligence-mcp": "index.js"
10
+ },
11
+ "scripts": {
12
+ "start": "node index.js",
13
+ "check": "node --check index.js"
14
+ },
15
+ "engines": {
16
+ "node": ">=18"
17
+ }
18
18
  }