mio-agent-runtime 0.15.0 → 0.16.0

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.
package/bin/mio.js CHANGED
@@ -24,6 +24,7 @@ const { createMemoryStore } = require('../server/memory-store.js')
24
24
  const { createExperienceStore } = require('../server/experience-store.js')
25
25
  const { createPolicyStore } = require('../server/policy-store.js')
26
26
  const { CreativityEngine, sourcesFromInsights, adoptHypothesis } = require('../server/creativity-engine.js')
27
+ const { mechanismRegistry, mechanismPromote, mechanismRollback } = require('../server/mechanism-registry.js')
27
28
  const { buildAutoSources, topUpSources } = require('../server/creativity-sources.js')
28
29
  const { runIdeaGenerate, groundingFrom } = require('../server/idea-generate.js')
29
30
  const { createAgentStore } = require('../server/agent-store.js')
@@ -71,15 +72,11 @@ function readJsonl(file) {
71
72
 
72
73
  function projectName() {
73
74
  try {
74
- const commonDir = execFileSync(
75
- 'git',
76
- ['rev-parse', '--path-format=absolute', '--git-common-dir'],
77
- {
78
- cwd: process.cwd(),
79
- encoding: 'utf8',
80
- stdio: ['ignore', 'pipe', 'ignore'],
81
- }
82
- ).trim()
75
+ const commonDir = execFileSync('git', ['rev-parse', '--path-format=absolute', '--git-common-dir'], {
76
+ cwd: process.cwd(),
77
+ encoding: 'utf8',
78
+ stdio: ['ignore', 'pipe', 'ignore'],
79
+ }).trim()
83
80
  if (commonDir) return path.basename(path.dirname(commonDir))
84
81
  } catch (_) {}
85
82
  return path.basename(process.cwd())
@@ -193,7 +190,7 @@ function printMigrationPlan(plan, useJson) {
193
190
  if (useJson) return jsonOrText(plan, true)
194
191
  console.log(`Migration plan: ${plan.ready ? 'ready' : 'conflicts'}`)
195
192
  console.log(
196
- `legacy=${plan.summary.legacy} modular=${plan.summary.modular} toCreate=${plan.summary.toCreate} conflicts=${plan.summary.conflicts}`
193
+ `legacy=${plan.summary.legacy} modular=${plan.summary.modular} toCreate=${plan.summary.toCreate} conflicts=${plan.summary.conflicts}`,
197
194
  )
198
195
  }
199
196
 
@@ -457,7 +454,9 @@ function splitTagsOption(args, name) {
457
454
  function recallCommand(args, useJson) {
458
455
  const query = args[1]
459
456
  if (!query) {
460
- console.error('Usage: mio recall "<query>" [--project name] [--scope project|global|all] [--kind kind] [--tags a,b] [--limit n] [--json]')
457
+ console.error(
458
+ 'Usage: mio recall "<query>" [--project name] [--scope project|global|all] [--kind kind] [--tags a,b] [--limit n] [--json]',
459
+ )
461
460
  process.exitCode = 1
462
461
  return
463
462
  }
@@ -479,9 +478,7 @@ function recallCommand(args, useJson) {
479
478
  return
480
479
  }
481
480
  if (useJson) return jsonOrText(result, true)
482
- console.log(
483
- `Mio memory: ${result.count} result(s) for "${result.query}" (project=${result.project}, scope=${result.scope})`
484
- )
481
+ console.log(`Mio memory: ${result.count} result(s) for "${result.query}" (project=${result.project}, scope=${result.scope})`)
485
482
  result.results.forEach((record, index) => {
486
483
  const date = (record.timestamp || '').slice(0, 10)
487
484
  console.log(`${index + 1}. [${record.kind || 'note'}] ${record.content}`)
@@ -523,9 +520,7 @@ function tracesCommand(args, useJson) {
523
520
  .filter(([, value]) => value !== null && value !== undefined)
524
521
  .map(([key, value]) => `${key}=${value}`)
525
522
  .join(', ')
526
- console.log(
527
- `Mio traces: ${result.matched} matched / ${result.total} total${filters ? ' (' + filters + ')' : ''}`
528
- )
523
+ console.log(`Mio traces: ${result.matched} matched / ${result.total} total${filters ? ' (' + filters + ')' : ''}`)
529
524
  const summary = Object.entries(result.summary.byOutcome)
530
525
  .map(([key, value]) => `${key}=${value}`)
531
526
  .join(' ')
@@ -534,7 +529,7 @@ function tracesCommand(args, useJson) {
534
529
  const time = (trace.timestamp || '').replace('T', ' ').slice(0, 19)
535
530
  const brief = trace.payload && trace.payload.summary ? ' | ' + String(trace.payload.summary).slice(0, 100) : ''
536
531
  console.log(
537
- `${index + 1}. ${time} [${trace.event_type || '?'}${trace.outcome ? '/' + trace.outcome : ''}] ${trace.agent || '?'} @ ${trace.project || '?'}${brief}`
532
+ `${index + 1}. ${time} [${trace.event_type || '?'}${trace.outcome ? '/' + trace.outcome : ''}] ${trace.agent || '?'} @ ${trace.project || '?'}${brief}`,
538
533
  )
539
534
  console.log(` ${trace.id} trace_id=${trace.trace_id || '-'}`)
540
535
  })
@@ -587,15 +582,11 @@ function digestCommand(args, useJson) {
587
582
  targetCwds = [explicitCwd]
588
583
  } else if (explicitProject) {
589
584
  const wanted = String(explicitProject).toLowerCase()
590
- targetCwds = Object.keys(state.contexts).filter(
591
- (cwd) => path.basename(cwd).toLowerCase() === wanted,
592
- )
585
+ targetCwds = Object.keys(state.contexts).filter((cwd) => path.basename(cwd).toLowerCase() === wanted)
593
586
  } else {
594
587
  // No explicit target: only write to workspaces this digest has data for.
595
588
  // A workspace with no matching project gets nothing.
596
- targetCwds = Object.keys(state.contexts).filter((cwd) =>
597
- projectLine.has(path.basename(cwd).toLowerCase()),
598
- )
589
+ targetCwds = Object.keys(state.contexts).filter((cwd) => projectLine.has(path.basename(cwd).toLowerCase()))
599
590
  }
600
591
 
601
592
  let written = 0
@@ -633,9 +624,7 @@ function digestCommand(args, useJson) {
633
624
  console.log(report.markdown)
634
625
  console.log(`Report saved: ${reportFile}`)
635
626
  if (report.writeBack) {
636
- console.log(
637
- `Write-back: ${report.writeBack.workspaces} workspace(s), ${report.writeBack.skipped} skipped (no digest data)`,
638
- )
627
+ console.log(`Write-back: ${report.writeBack.workspaces} workspace(s), ${report.writeBack.skipped} skipped (no digest data)`)
639
628
  if (report.writeBack.failures && report.writeBack.failures.length > 0) {
640
629
  console.error(` ${report.writeBack.failures.length} write-back failure(s):`)
641
630
  for (const f of report.writeBack.failures) console.error(` - ${f.workspace}: ${f.error}`)
@@ -665,7 +654,7 @@ function pruneCommand(args, useJson) {
665
654
  }
666
655
  if (useJson) return jsonOrText(result, true)
667
656
  console.log(
668
- `Prune ${dryRun ? 'plan (dry-run)' : 'result'}: cutoff ${result.cutoff}, days=${days}${includeMemory ? ', memory included' : ''}`
657
+ `Prune ${dryRun ? 'plan (dry-run)' : 'result'}: cutoff ${result.cutoff}, days=${days}${includeMemory ? ', memory included' : ''}`,
669
658
  )
670
659
  for (const file of result.files) {
671
660
  console.log(`- ${file.file}: ${file.total} total -> keep ${file.kept}, remove ${file.removed}`)
@@ -678,7 +667,9 @@ function pruneCommand(args, useJson) {
678
667
  function rememberCommand(args, useJson) {
679
668
  const content = args[1]
680
669
  if (!content) {
681
- console.error('Usage: mio remember "<content>" [--kind decision|context|problem|note] [--tags a,b] [--hypothesis-id id] [--scope project|global] [--project name] [--json]')
670
+ console.error(
671
+ 'Usage: mio remember "<content>" [--kind decision|context|problem|note] [--tags a,b] [--hypothesis-id id] [--scope project|global] [--project name] [--json]',
672
+ )
682
673
  process.exitCode = 1
683
674
  return
684
675
  }
@@ -710,8 +701,18 @@ function rememberCommand(args, useJson) {
710
701
  // Every flag that consumes the next token. A positional directly after one of
711
702
  // these is that flag's value, not an id.
712
703
  const VALUE_FLAGS = new Set([
713
- '--ids', '--reason', '--project', '--limit', '--scope', '--keep',
714
- '--by', '--notes', '--source-agent', '--target-agent', '--experience-id', '--status',
704
+ '--ids',
705
+ '--reason',
706
+ '--project',
707
+ '--limit',
708
+ '--scope',
709
+ '--keep',
710
+ '--by',
711
+ '--notes',
712
+ '--source-agent',
713
+ '--target-agent',
714
+ '--experience-id',
715
+ '--status',
715
716
  ])
716
717
 
717
718
  // Accept ids both as `--ids a,b,c` and as bare positionals
@@ -741,9 +742,7 @@ function collectIds(flags) {
741
742
 
742
743
  function printMemoryAnalyze(result) {
743
744
  const project = result.project || 'all'
744
- console.log(
745
- `Memory analyze: ${result.total} active, ${result.archived} archived (project=${project})`,
746
- )
745
+ console.log(`Memory analyze: ${result.total} active, ${result.archived} archived (project=${project})`)
747
746
  console.log(`layers: project=${result.layers.project} global=${result.layers.global}`)
748
747
  const kinds = Object.entries(result.byKind)
749
748
  if (kinds.length > 0) {
@@ -813,9 +812,7 @@ function printMemoryMerge(result) {
813
812
  return
814
813
  }
815
814
 
816
- console.log(
817
- `Merged ${result.archivedCount} record(s) into ${result.survivor.id} (project=${result.project || 'current'})`,
818
- )
815
+ console.log(`Merged ${result.archivedCount} record(s) into ${result.survivor.id} (project=${result.project || 'current'})`)
819
816
  console.log(`survivor: ${result.survivor.contentLength} chars, ${result.survivor.timestamp || 'no timestamp'}`)
820
817
  if (result.divergentContent) console.log('note: content differed across members; the survivor body was chosen explicitly')
821
818
  console.log(`supersedes: ${result.survivor.supersedes.join(', ')}`)
@@ -921,7 +918,11 @@ function memoryCommand(args, useJson) {
921
918
  const matched = all.filter((r) => idSet.has(r.id))
922
919
  console.log(`Forget preview: ${ids.length} id(s) (project=${previewProject})`)
923
920
  for (const record of matched) {
924
- console.log(` ${record.id} ${String(record.content || '').replace(/\s+/g, ' ').slice(0, 80)}`)
921
+ console.log(
922
+ ` ${record.id} ${String(record.content || '')
923
+ .replace(/\s+/g, ' ')
924
+ .slice(0, 80)}`,
925
+ )
925
926
  }
926
927
  for (const id of ids) {
927
928
  if (!matched.some((r) => r.id === id)) console.log(` ${id} (not found)`)
@@ -1075,9 +1076,7 @@ Options:
1075
1076
  }
1076
1077
 
1077
1078
  function printExperienceList(result) {
1078
- console.log(
1079
- `Experience reuse: ${result.count} shown of ${result.total} (project=${result.project || 'all'}, status=${result.status})`,
1080
- )
1079
+ console.log(`Experience reuse: ${result.count} shown of ${result.total} (project=${result.project || 'all'}, status=${result.status})`)
1081
1080
  if (result.count === 0) {
1082
1081
  console.log('No reuse records match.')
1083
1082
  return
@@ -1086,23 +1085,15 @@ function printExperienceList(result) {
1086
1085
  const state = record.confirmed ? 'confirmed' : 'pending'
1087
1086
  const badge = record.reuse && record.behaviorChanged && record.outcomeImproved ? 'verified' : state
1088
1087
  const arrow = `${record.sourceAgent || '?'} -> ${record.targetAgent || '?'}`
1089
- const flags = [
1090
- record.reuse ? 'reused' : null,
1091
- record.behaviorChanged ? 'changed' : null,
1092
- record.outcomeImproved ? 'improved' : null,
1093
- ]
1088
+ const flags = [record.reuse ? 'reused' : null, record.behaviorChanged ? 'changed' : null, record.outcomeImproved ? 'improved' : null]
1094
1089
  .filter(Boolean)
1095
1090
  .join(',')
1096
1091
  console.log(`${index + 1}. [${badge}] ${record.experienceId} ${arrow}`)
1097
- console.log(
1098
- ` ${flags || 'no effect flags'} | ${(record.timestamp || '').slice(0, 19)} | ${record.id}`,
1099
- )
1092
+ console.log(` ${flags || 'no effect flags'} | ${(record.timestamp || '').slice(0, 19)} | ${record.id}`)
1100
1093
  if (record.notes) console.log(` note: ${record.notes}`)
1101
1094
  })
1102
1095
  // Only auto_claims are confirmable — experience.confirm rejects anything else.
1103
- const pending = result.records
1104
- .filter((record) => record.source === 'auto_claim' && !record.confirmed)
1105
- .map((record) => record.id)
1096
+ const pending = result.records.filter((record) => record.source === 'auto_claim' && !record.confirmed).map((record) => record.id)
1106
1097
  if (pending.length > 0) {
1107
1098
  console.log('')
1108
1099
  console.log(
@@ -1158,11 +1149,7 @@ function experienceCommand(args, useJson) {
1158
1149
  return
1159
1150
  }
1160
1151
  // Absent = keep whatever the auto-claim recorded; --no-improved rejects it.
1161
- const improved = flagPresent(flags, '--no-improved')
1162
- ? false
1163
- : flagPresent(flags, '--outcome-improved')
1164
- ? true
1165
- : undefined
1152
+ const improved = flagPresent(flags, '--no-improved') ? false : flagPresent(flags, '--outcome-improved') ? true : undefined
1166
1153
  result = store.confirmReuse({
1167
1154
  ids,
1168
1155
  outcomeImproved: improved,
@@ -1260,9 +1247,7 @@ function printPolicyCheck(result) {
1260
1247
  console.log('Try a more specific action, e.g. mio policy check "npm publish".')
1261
1248
  } else if (diag && diag.lowSample) {
1262
1249
  console.log('')
1263
- console.log(
1264
- `NOTE: only ${diag.sampleSize} matching trace(s); treat the level above as a weak signal.`,
1265
- )
1250
+ console.log(`NOTE: only ${diag.sampleSize} matching trace(s); treat the level above as a weak signal.`)
1266
1251
  }
1267
1252
 
1268
1253
  console.log(`\n${result.suggestion}`)
@@ -1500,9 +1485,7 @@ function insightGenerateCommand(args, useJson) {
1500
1485
  return Promise.resolve(result).then((resolved) => {
1501
1486
  if (useJson) return jsonOrText(resolved, true)
1502
1487
  if (!resolved || resolved.generated === 0) {
1503
- console.log(
1504
- `No insights generated: ${(resolved && resolved.reason) || 'nothing notable in the given context'}`
1505
- )
1488
+ console.log(`No insights generated: ${(resolved && resolved.reason) || 'nothing notable in the given context'}`)
1506
1489
  return
1507
1490
  }
1508
1491
  console.log(`Generated ${resolved.generated} insight(s)`)
@@ -1623,7 +1606,10 @@ function printObserverEssays(essays) {
1623
1606
  }
1624
1607
  for (const essay of essays) {
1625
1608
  console.log(`- ${essay.file} (${essay.type}, ${String(essay.created).slice(0, 10)})`)
1626
- const firstLine = String(essay.content || '').split('\n').find((l) => l.trim()) || ''
1609
+ const firstLine =
1610
+ String(essay.content || '')
1611
+ .split('\n')
1612
+ .find((l) => l.trim()) || ''
1627
1613
  if (firstLine) console.log(` ${firstLine.replace(/\s+/g, ' ').slice(0, 120)}`)
1628
1614
  }
1629
1615
  console.log(`\n${essays.length} essay(s)`)
@@ -1960,7 +1946,9 @@ function printObserverServe(result) {
1960
1946
  }
1961
1947
  console.log(`Observer research scheduler running (base-dir=${result.baseDir})`)
1962
1948
  console.log(` ${result.schedule ? result.schedule.collectors : 'collectors started'}`)
1963
- console.log(` pipeline: first tick ${result.schedule ? result.schedule.pipelineFirstTickMs : 5000}ms, then every ${result.schedule ? result.schedule.pipelineTickMs : 60000}ms`)
1949
+ console.log(
1950
+ ` pipeline: first tick ${result.schedule ? result.schedule.pipelineFirstTickMs : 5000}ms, then every ${result.schedule ? result.schedule.pipelineTickMs : 60000}ms`,
1951
+ )
1964
1952
  console.log(' Stops with Ctrl+C (or `mio observe --stop` when started that way).')
1965
1953
  }
1966
1954
 
@@ -2104,7 +2092,9 @@ function printCreativityStatus(result) {
2104
2092
  console.log(` hypotheses: ${result.hypotheses} combos: ${result.combos} experiments: ${result.experiments}`)
2105
2093
  console.log(` active: ${result.active} validated: ${result.validated} rejected: ${result.rejected} draft: ${result.draft}`)
2106
2094
  const adoption = result.adoption || { adopted: 0, claimed: 0, evidenced: 0 }
2107
- console.log(` adoption: ${adoption.adopted} adopted (events=${adoption.claimed} tags=${adoption.evidenced}) — derived join, not a metric`)
2095
+ console.log(
2096
+ ` adoption: ${adoption.adopted} adopted (events=${adoption.claimed} tags=${adoption.evidenced}) — derived join, not a metric`,
2097
+ )
2108
2098
  if (result.recentIdeas.length === 0) {
2109
2099
  console.log('No hypotheses yet.')
2110
2100
  return
@@ -2125,7 +2115,9 @@ function printCreativityList(items) {
2125
2115
  items.forEach((h, index) => {
2126
2116
  const when = h.createdAt ? new Date(h.createdAt).toISOString().slice(0, 19).replace('T', ' ') : ''
2127
2117
  const labels = Array.isArray(h.sourceLabels) && h.sourceLabels.length > 0 ? h.sourceLabels.join(' + ') : '—'
2128
- console.log(`${index + 1}. [${h.status}]${h.adopted ? ' [adopted]' : ''} ${h.title} (N=${h.novelty} F=${h.feasibility} I=${h.impact} score=${h.score}${h.noveltyScore !== undefined ? ` noveltyScore=${h.noveltyScore}` : ''})`)
2118
+ console.log(
2119
+ `${index + 1}. [${h.status}]${h.adopted ? ' [adopted]' : ''} ${h.title} (N=${h.novelty} F=${h.feasibility} I=${h.impact} score=${h.score}${h.noveltyScore !== undefined ? ` noveltyScore=${h.noveltyScore}` : ''})`,
2120
+ )
2129
2121
  console.log(` ${labels} | ${when} | ${h.id}`)
2130
2122
  if (h.fermentCount) console.log(` fermented ${h.fermentCount}x`)
2131
2123
  })
@@ -2168,7 +2160,7 @@ function printCreativityErrors(errors, label) {
2168
2160
  if (!Array.isArray(errors) || errors.length === 0) return
2169
2161
  console.log(`\n${errors.length} ${label}(s) failed:`)
2170
2162
  for (const err of errors) {
2171
- const who = err.pair ? err.pair.join(' + ') : (err.title || err.id)
2163
+ const who = err.pair ? err.pair.join(' + ') : err.title || err.id
2172
2164
  console.log(`- ${who}: ${err.error}`)
2173
2165
  }
2174
2166
  }
@@ -2327,7 +2319,7 @@ function creativityAdoptCommand(args, useJson) {
2327
2319
  note: optionValue(flags, '--note'),
2328
2320
  },
2329
2321
  cliTaskStore().ingestObservation,
2330
- MIO_HOME
2322
+ MIO_HOME,
2331
2323
  )
2332
2324
  } catch (error) {
2333
2325
  console.error(error.message || error)
@@ -2408,7 +2400,9 @@ async function ideaGenerateCommand(args, useJson) {
2408
2400
  console.log(`Generated ${result.ideas.length} idea(s) (grounded with ${result.groundedWith} memories)`)
2409
2401
  result.ideas.forEach((idea) => {
2410
2402
  console.log(`- [${idea.hypothesis.status}] ${idea.title}`)
2411
- console.log(` novelty=${idea.hypothesis.novelty} feasibility=${idea.hypothesis.feasibility} impact=${idea.hypothesis.impact} | ${idea.hypothesis.id}`)
2403
+ console.log(
2404
+ ` novelty=${idea.hypothesis.novelty} feasibility=${idea.hypothesis.feasibility} impact=${idea.hypothesis.impact} | ${idea.hypothesis.id}`,
2405
+ )
2412
2406
  if (idea.provenance && idea.provenance.technique) console.log(` technique=${idea.provenance.technique}`)
2413
2407
  if (idea.hypothesis.rejectionReason) console.log(` rejected: ${idea.hypothesis.rejectionReason}`)
2414
2408
  })
@@ -2472,6 +2466,86 @@ function creativityCommand(args, useJson) {
2472
2466
  else printCreativityList(result)
2473
2467
  }
2474
2468
 
2469
+ function mechanismUsage(write = console.log) {
2470
+ write(`mio mechanism <subcommand> — mechanism registry (promotion/rollback)
2471
+
2472
+ Subcommands:
2473
+ mio mechanism registry List versions and promotion requests (--mechanism-id, --status)
2474
+ mio mechanism promote submit ... Submit a PromotionRequest (gate-checked)
2475
+ mio mechanism promote approve ... Approve a request (approver must differ from submitter)
2476
+ mio mechanism promote reject ... Reject a request
2477
+ mio mechanism rollback <mechanismId> Roll back the active version to its rollbackTo target
2478
+
2479
+ Options:
2480
+ --json Machine-readable output
2481
+
2482
+ Examples:
2483
+ mio mechanism registry
2484
+ mio mechanism promote submit --mechanism-id m-1 --version 1 --submitted-by codex
2485
+ mio mechanism promote approve --request-id pr-1 --approved-by other-agent
2486
+ mio mechanism rollback m-1`)
2487
+ }
2488
+
2489
+ function mechanismCommand(args, useJson) {
2490
+ const sub = args[1]
2491
+
2492
+ if (!sub || sub === 'help' || sub === '--help' || sub === '-h') {
2493
+ mechanismUsage()
2494
+ if (!sub) process.exitCode = 1
2495
+ return
2496
+ }
2497
+
2498
+ const flags = args.slice(2)
2499
+
2500
+ try {
2501
+ if (sub === 'registry') {
2502
+ const result = mechanismRegistry(
2503
+ { mechanismId: optionValue(flags, '--mechanism-id'), status: optionValue(flags, '--status') },
2504
+ MIO_HOME,
2505
+ )
2506
+ return jsonOrText(result, useJson)
2507
+ }
2508
+
2509
+ if (sub === 'promote') {
2510
+ const action = flags[0]
2511
+ const result = mechanismPromote(
2512
+ {
2513
+ action,
2514
+ mechanismId: optionValue(flags, '--mechanism-id'),
2515
+ version: parseNumberOption(flags, '--version'),
2516
+ hypothesisId: optionValue(flags, '--hypothesis-id'),
2517
+ experimentRunIds: optionValues(flags, '--experiment-run-ids'),
2518
+ submittedBy: optionValue(flags, '--submitted-by'),
2519
+ requestId: optionValue(flags, '--request-id'),
2520
+ approvedBy: optionValue(flags, '--approved-by'),
2521
+ reason: optionValue(flags, '--reason'),
2522
+ },
2523
+ MIO_HOME,
2524
+ )
2525
+ return jsonOrText(result, useJson)
2526
+ }
2527
+
2528
+ if (sub === 'rollback') {
2529
+ const mechanismId = args[2]
2530
+ if (!mechanismId) {
2531
+ console.error('mio mechanism rollback requires <mechanismId>')
2532
+ console.error('Usage: mio mechanism rollback <mechanismId> [--json]')
2533
+ process.exitCode = 1
2534
+ return
2535
+ }
2536
+ const result = mechanismRollback({ mechanismId }, MIO_HOME)
2537
+ return jsonOrText(result, useJson)
2538
+ }
2539
+
2540
+ console.error(`Unknown mechanism subcommand: ${sub}`)
2541
+ mechanismUsage(console.error)
2542
+ process.exitCode = 1
2543
+ } catch (error) {
2544
+ console.error(error.message || error)
2545
+ process.exitCode = 1
2546
+ }
2547
+ }
2548
+
2475
2549
  function readConfig() {
2476
2550
  const fallback = { version: 1, home: MIO_HOME, agents: {} }
2477
2551
  if (!fs.existsSync(CONFIG_FILE)) return fallback
@@ -2538,7 +2612,7 @@ function configShowCommand(useJson) {
2538
2612
  configured: isLlmConfigured(),
2539
2613
  },
2540
2614
  },
2541
- true
2615
+ true,
2542
2616
  )
2543
2617
  }
2544
2618
 
@@ -2548,7 +2622,7 @@ function configShowCommand(useJson) {
2548
2622
  console.log('LLM (effective):')
2549
2623
  console.log(` apiUrl: ${effective.apiUrl} [${LLM_SOURCE_LABELS[sources.apiUrl]}]`)
2550
2624
  console.log(
2551
- ` apiKey: ${effective.apiKey ? `${maskSecret(effective.apiKey)} [${LLM_SOURCE_LABELS[sources.apiKey]}]` : '(none / unauthenticated)'}`
2625
+ ` apiKey: ${effective.apiKey ? `${maskSecret(effective.apiKey)} [${LLM_SOURCE_LABELS[sources.apiKey]}]` : '(none / unauthenticated)'}`,
2552
2626
  )
2553
2627
  console.log(` model: ${effective.model} [${LLM_SOURCE_LABELS[sources.model]}]`)
2554
2628
  console.log('')
@@ -2632,7 +2706,7 @@ function configLlmCommand(flags, useJson) {
2632
2706
  },
2633
2707
  configFile: CONFIG_FILE,
2634
2708
  },
2635
- true
2709
+ true,
2636
2710
  )
2637
2711
  }
2638
2712
 
@@ -2738,11 +2812,8 @@ function statusCommand(useJson) {
2738
2812
  dataDir: MIO_HOME,
2739
2813
  projectName: () => null,
2740
2814
  }).listReuse({ status: 'pending', limit: 100 }).records
2741
- return records.filter(
2742
- (record) =>
2743
- String(record.sourceAgent || '').toLowerCase() !==
2744
- String(record.targetAgent || '').toLowerCase()
2745
- ).length
2815
+ return records.filter((record) => String(record.sourceAgent || '').toLowerCase() !== String(record.targetAgent || '').toLowerCase())
2816
+ .length
2746
2817
  } catch {
2747
2818
  return 0
2748
2819
  }
@@ -2789,11 +2860,9 @@ function statusCommand(useJson) {
2789
2860
  console.log(`Observer: ${observer.isRunning(MIO_HOME) ? 'running (pid ' + observer.readPid(MIO_HOME) + ')' : 'not running'}`)
2790
2861
  if (pendingAutoClaims > 0) {
2791
2862
  console.log(
2792
- `Pending auto-claims: ${pendingAutoClaims} (${pendingCrossAgent} cross-agent) -- only cross-agent claims whose target output actually cites the source memory may be confirmed; same-agent / weak / self-reported must NOT be (ADR-017).`
2793
- )
2794
- console.log(
2795
- ` review: \`mio experience list --status pending\` then \`mio experience confirm --ids <id,...>\``
2863
+ `Pending auto-claims: ${pendingAutoClaims} (${pendingCrossAgent} cross-agent) -- only cross-agent claims whose target output actually cites the source memory may be confirmed; same-agent / weak / self-reported must NOT be (ADR-017).`,
2796
2864
  )
2865
+ console.log(` review: \`mio experience list --status pending\` then \`mio experience confirm --ids <id,...>\``)
2797
2866
  }
2798
2867
  }
2799
2868
 
@@ -2928,9 +2997,7 @@ function agentsCommand(args, useJson) {
2928
2997
  }
2929
2998
  if (useJson) return jsonOrText(result, true)
2930
2999
  console.log(`Registered ${result.agentId} (project=${project})`)
2931
- console.log(
2932
- ` ${result.registered ? 'created' : `updated (session ${result.sessionCount})`} | host=${result.hostType}`,
2933
- )
3000
+ console.log(` ${result.registered ? 'created' : `updated (session ${result.sessionCount})`} | host=${result.hostType}`)
2934
3001
  if (result.capabilities && result.capabilities.length > 0) {
2935
3002
  console.log(` capabilities: ${result.capabilities.join(', ')}`)
2936
3003
  }
@@ -2951,9 +3018,7 @@ function printAgentList(result) {
2951
3018
  for (const a of result.agents) {
2952
3019
  const caps = Array.isArray(a.capabilities) && a.capabilities.length > 0 ? ` [${a.capabilities.join(', ')}]` : ''
2953
3020
  console.log(`${a.agentId} (${a.hostType})${caps} project=${a.project || '-'}`)
2954
- console.log(
2955
- ` sessions=${a.sessionCount || 0} tasks=${a.taskCount} success=${a.successCount} failure=${a.failureCount} | ${a.id}`,
2956
- )
3021
+ console.log(` sessions=${a.sessionCount || 0} tasks=${a.taskCount} success=${a.successCount} failure=${a.failureCount} | ${a.id}`)
2957
3022
  }
2958
3023
  }
2959
3024
 
@@ -2967,9 +3032,7 @@ function printAgentReport(result) {
2967
3032
  const o = r.taskOutcomes
2968
3033
  const when = r.lastSeenAt ? r.lastSeenAt.slice(0, 19).replace('T', ' ') : 'unknown'
2969
3034
  console.log(`${r.agentId} (${r.hostType}) ${r.active ? 'active' : 'idle'}`)
2970
- console.log(
2971
- ` tasks: ${o.total} total, ${o.success} success, ${o.failure} failure (${o.successRate}% success)`,
2972
- )
3035
+ console.log(` tasks: ${o.total} total, ${o.success} success, ${o.failure} failure (${o.successRate}% success)`)
2973
3036
  console.log(` memories: ${r.memories} experience reuses: ${r.experienceReuses.total} (verified ${r.experienceReuses.verified})`)
2974
3037
  console.log(` last seen: ${when} | sessions=${r.sessionCount}`)
2975
3038
  }
@@ -2993,12 +3056,8 @@ function printRate(label, metric, numeratorKey, denominatorKey, unit, rateKey =
2993
3056
 
2994
3057
  function printEvaluation(result) {
2995
3058
  const s = result.sample
2996
- console.log(
2997
- `ADR-017 evaluation${result.project ? ` (project=${result.project})` : ''}${result.since ? ` since ${result.since}` : ''}`,
2998
- )
2999
- console.log(
3000
- ` sample: queries=${s.queries} routeHits=${s.routeHits} reuses=${s.reuses} traces=${s.traces} agents=${s.agents}`,
3001
- )
3059
+ console.log(`ADR-017 evaluation${result.project ? ` (project=${result.project})` : ''}${result.since ? ` since ${result.since}` : ''}`)
3060
+ console.log(` sample: queries=${s.queries} routeHits=${s.routeHits} reuses=${s.reuses} traces=${s.traces} agents=${s.agents}`)
3002
3061
  console.log(' 1. route adoption rate (hit and acted on / hits)')
3003
3062
  printRate('adoption', result.routeAdoption, 'adopted', 'routeHits', 'experience hits')
3004
3063
  console.log(' 2. behaviour change rate (confirmed behaviorChanged / reuses)')
@@ -3012,9 +3071,7 @@ function printEvaluation(result) {
3012
3071
  if (base) {
3013
3072
  const now = result.behaviorChange.verified
3014
3073
  const verdict = now >= base.observed ? 'at or above' : now >= base.required ? 'above threshold, below baseline' : 'BELOW BASELINE'
3015
- console.log(
3016
- ` baseline ${result.baseline.date}: ${base.observed} (required ${base.required}) -- now ${now}, ${verdict}`,
3017
- )
3074
+ console.log(` baseline ${result.baseline.date}: ${base.observed} (required ${base.required}) -- now ${now}, ${verdict}`)
3018
3075
  }
3019
3076
  console.log(' 3. recall quality (queries with results that led to a reuse)')
3020
3077
  printRate('yield', result.recallQuality, 'queriesLinkedToReuse', 'queriesWithResults', 'queries', 'yield')
@@ -3393,11 +3450,7 @@ function installCommand(host, useJson) {
3393
3450
  if (!observerCycleOk) {
3394
3451
  console.error('Warning: observer cycle failed during install; run `mio observe --once` manually.')
3395
3452
  }
3396
- console.log(
3397
- observer.isRunning(MIO_HOME)
3398
- ? 'Observer daemon running.'
3399
- : 'Observer daemon not running. Run `mio observe --start`.'
3400
- )
3453
+ console.log(observer.isRunning(MIO_HOME) ? 'Observer daemon running.' : 'Observer daemon not running. Run `mio observe --start`.')
3401
3454
  }
3402
3455
 
3403
3456
  function mcpCommand() {
@@ -3438,7 +3491,8 @@ function observeCommand(args, jsonFlag = false) {
3438
3491
  console.log(result.started ? 'Observer started.' : 'Observer already running.')
3439
3492
  if (researchResult) {
3440
3493
  if (researchResult.skipped) console.log('Research scheduler skipped: ' + researchResult.skipped)
3441
- else if (researchResult.started) console.log('Research scheduler started (pid ' + researchResult.pid + ', base-dir ' + researchResult.baseDir + ')')
3494
+ else if (researchResult.started)
3495
+ console.log('Research scheduler started (pid ' + researchResult.pid + ', base-dir ' + researchResult.baseDir + ')')
3442
3496
  else console.log('Research scheduler already running (pid ' + researchResult.pid + ')')
3443
3497
  }
3444
3498
  return
@@ -3447,10 +3501,7 @@ function observeCommand(args, jsonFlag = false) {
3447
3501
  const result = observer.stopBackground(MIO_HOME)
3448
3502
  const researchResult = observer.stopResearchBackground(MIO_HOME)
3449
3503
  if (useJson) {
3450
- return jsonOrText(
3451
- { ...result, research: { running: false, stopped: researchResult.stopped, pid: researchResult.pid } },
3452
- true
3453
- )
3504
+ return jsonOrText({ ...result, research: { running: false, stopped: researchResult.stopped, pid: researchResult.pid } }, true)
3454
3505
  }
3455
3506
  console.log(result.stopped ? 'Observer stopped.' : 'Observer was not running.')
3456
3507
  console.log(researchResult.stopped ? 'Research scheduler stopped.' : 'Research scheduler was not running.')
@@ -3464,9 +3515,7 @@ function observeCommand(args, jsonFlag = false) {
3464
3515
  const researchInfo = { running: researchRunning, pid: researchPid, logFile: observer.researchLogFile(MIO_HOME) }
3465
3516
  if (useJson) return jsonOrText({ running, pid, research: researchInfo }, true)
3466
3517
  console.log(running ? 'Observer: running (pid ' + pid + ')' : 'Observer: not running')
3467
- console.log(
3468
- researchRunning ? 'Research scheduler: running (pid ' + researchPid + ')' : 'Research scheduler: not running'
3469
- )
3518
+ console.log(researchRunning ? 'Research scheduler: running (pid ' + researchPid + ')' : 'Research scheduler: not running')
3470
3519
  return
3471
3520
  }
3472
3521
  if (flags.includes('--research') && !flags.includes('--start')) {
@@ -3475,11 +3524,7 @@ function observeCommand(args, jsonFlag = false) {
3475
3524
  return
3476
3525
  }
3477
3526
  if (flags.includes('--once')) {
3478
- const res = observer.runCycle(
3479
- MIO_HOME,
3480
- observer.loadState(MIO_HOME),
3481
- observer.createSinks(MIO_HOME)
3482
- )
3527
+ const res = observer.runCycle(MIO_HOME, observer.loadState(MIO_HOME), observer.createSinks(MIO_HOME))
3483
3528
  if (useJson) return jsonOrText(res, true)
3484
3529
  console.log('Observed files=' + res.files + ' lines=' + res.lines + ' outcomes=' + res.outcomes)
3485
3530
  return
@@ -3540,6 +3585,9 @@ Usage:
3540
3585
  mio creativity generate Generate hypotheses from 2+ --source "name|content" (or --from-insights; calls an LLM)
3541
3586
  mio creativity ferment Review and refine active hypotheses (calls an LLM)
3542
3587
  mio creativity adopt Record an adoption event for a stored hypothesis (writes traces only)
3588
+ mio mechanism registry List mechanism versions and promotion requests
3589
+ mio mechanism promote Submit/approve/reject a PromotionRequest (approver must differ from submitter)
3590
+ mio mechanism rollback Roll back the active version of a mechanism
3543
3591
  mio idea generate --goal "..." Grounded idea pipeline: auto sources, novelty gate, persisted (calls an LLM)
3544
3592
  mio insight status Insight counts: total, reported, unreported, high-value
3545
3593
  mio insight list List insights (--unreported, --min-score N, --detector X, --limit N)
@@ -3604,6 +3652,8 @@ async function main() {
3604
3652
  return policyCommand(args, useJson)
3605
3653
  case 'creativity':
3606
3654
  return creativityCommand(args, useJson)
3655
+ case 'mechanism':
3656
+ return mechanismCommand(args, useJson)
3607
3657
  case 'idea':
3608
3658
  return ideaCommand(args, useJson)
3609
3659
  case 'insight':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mio-agent-runtime",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Mio Agent Runtime installer and MCP intelligence layer",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -36,7 +36,7 @@
36
36
  "@akemi-mio/evolution-scheduler": "^0.1.0",
37
37
  "@akemi-mio/observer": "^0.1.5",
38
38
  "@akemi-mio/insight": "^0.1.1",
39
- "@akemi-mio/creativity": "^0.1.0"
39
+ "@akemi-mio/creativity": "^0.1.1"
40
40
  },
41
41
  "main": "index.js",
42
42
  "directories": {