mio-agent-runtime 0.5.11 → 0.5.13

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/README.md CHANGED
@@ -244,6 +244,7 @@ WorkBuddy ─┘ + Observer ......... automatic data collection
244
244
  | >= 0.5.9 | `mio uninstall <host>` command |
245
245
  | >= 0.5.10 | `mio upgrade` and `mio doctor` commands |
246
246
  | >= 0.5.11 | Live web dashboard (`mio dashboard` + `mio.dashboard.*`) |
247
+ | >= 0.5.12 | Observer reliability: all outcomes write back (not just success); Hermes cwd hardening; write-back diagnostics |
247
248
 
248
249
  ---
249
250
 
@@ -55,8 +55,8 @@ function runHermes(args) {
55
55
  try {
56
56
  const isCmdShim = Boolean(bin && /\.(cmd|bat)$/i.test(bin))
57
57
  res = bin
58
- ? spawnSync(bin, args, { encoding: 'utf8', timeout: 60000, windowsHide: true, input: input, shell: isCmdShim })
59
- : spawnSync('hermes', args, { encoding: 'utf8', timeout: 60000, shell: true, windowsHide: true, input: input })
58
+ ? spawnSync(bin, args, { encoding: 'utf8', timeout: 60000, windowsHide: true, input: input, shell: isCmdShim, cwd: hermesHome() })
59
+ : spawnSync('hermes', args, { encoding: 'utf8', timeout: 60000, shell: true, windowsHide: true, input: input, cwd: hermesHome() })
60
60
  } catch (_) {
61
61
  return null
62
62
  }
@@ -300,7 +300,10 @@ function updateProjectContext(state, cwd, line) {
300
300
  content = content.trimEnd() + '\n\n' + block + '\n'
301
301
  fs.mkdirSync(path.dirname(target), { recursive: true })
302
302
  fs.writeFileSync(target, content, 'utf8')
303
- } catch (_) {}
303
+ log(homeDir(), 'write-back OK: MIO_CONTEXT -> ' + target)
304
+ } catch (e) {
305
+ log(homeDir(), 'write-back FAIL: MIO_CONTEXT -> ' + target + ': ' + (e && e.message || e))
306
+ }
304
307
  }
305
308
 
306
309
  function localDateKey(ts) {
@@ -326,7 +329,10 @@ function writeWorkbuddyDigest(turn, outcome, summary) {
326
329
  '\n## Mio 自动摘要 (' + time + ')\n' +
327
330
  '- outcome: ' + outcome + ' | tools: ' + turn.toolCount + ' | ' + summary.slice(0, 160) + '\n'
328
331
  fs.appendFileSync(file, entry, 'utf8')
329
- } catch (_) {}
332
+ log(homeDir(), 'write-back OK: workbuddy digest -> ' + file)
333
+ } catch (e) {
334
+ log(homeDir(), 'write-back FAIL: workbuddy digest -> ' + file + ': ' + (e && e.message || e))
335
+ }
330
336
  }
331
337
 
332
338
  function emitWorkbuddyOutcome(turn, sinks, state) {
@@ -370,6 +376,7 @@ function emitWorkbuddyOutcome(turn, sinks, state) {
370
376
  project: turn.project,
371
377
  source: 'workbuddy-observer',
372
378
  })
379
+ log(homeDir(), '[workbuddy] write-back: ' + memLabel + ' -> memory + ' + (turn.cwd || '?') + '/AGENTS.md')
373
380
  writeWorkbuddyDigest(turn, outcome, summary)
374
381
  var ctxTime = new Date(Number(turn.ts) || Date.now()).toLocaleString('zh-CN', { hour12: false })
375
382
  updateProjectContext(state, turn.cwd, ctxTime + ' | ' + outcome + ' | ' + summary.slice(0, 80))
@@ -800,6 +807,7 @@ function emitOpencodeOutcome(turn, sinks, state) {
800
807
  project: turn.project,
801
808
  source: 'opencode-observer',
802
809
  })
810
+ log(homeDir(), '[opencode] write-back: ' + memLabel + ' -> memory + ' + (turn.cwd || '?') + '/AGENTS.md')
803
811
  var ctxTime = new Date(Number(turn.ts) || Date.now()).toLocaleString('zh-CN', { hour12: false })
804
812
  updateProjectContext(state, turn.cwd, ctxTime + ' | ' + outcome + ' | ' + summary.slice(0, 80))
805
813
  }
@@ -1060,6 +1068,7 @@ function emitHermesOutcome(turn, sinks, state) {
1060
1068
  project: turn.project,
1061
1069
  source: 'hermes-observer',
1062
1070
  })
1071
+ log(homeDir(), '[hermes] write-back: ' + memLabel + ' -> memory')
1063
1072
  // Hermes reads AGENTS.md Context Files; write back only into a real repo
1064
1073
  // workspace so we never pollute the user's home directory.
1065
1074
  if (turn.cwd) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mio-agent-runtime",
3
- "version": "0.5.11",
3
+ "version": "0.5.13",
4
4
  "description": "Mio Agent Runtime installer and MCP intelligence layer",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -1662,6 +1662,90 @@ const TOOLS = [
1662
1662
  },
1663
1663
  ]
1664
1664
 
1665
+ function handleIdeaGenerate(args = {}) {
1666
+ const goal = String(args.goal || '').trim()
1667
+ if (!goal) throw new Error('idea.generate requires a goal')
1668
+ const numIdeas = Math.min(Math.max(Number(args.numIdeas) || 3, 1), 10)
1669
+ const context = args.context ? String(args.context).trim() : ''
1670
+ const constraints = Array.isArray(args.constraints) ? args.constraints.map(String) : []
1671
+
1672
+ // Query Mio memory for related context
1673
+ const relatedRecords = readJsonl(memoryPath)
1674
+ .filter(r => r.archived !== true)
1675
+ .filter(r => {
1676
+ const text = (r.content || '').toLowerCase()
1677
+ const goalWords = goal.toLowerCase().split(/\s+/).filter(w => w.length > 2)
1678
+ return goalWords.some(w => text.includes(w))
1679
+ })
1680
+ .slice(0, 8)
1681
+
1682
+ const relatedMemoryText = relatedRecords.length > 0
1683
+ ? relatedRecords.map(r => '- [' + r.kind + '] ' + (r.content || '').slice(0, 200)).join('\n')
1684
+ : '(no related memories found)'
1685
+
1686
+ const strategies = [
1687
+ {
1688
+ name: 'SCAMPER',
1689
+ prompt: 'Apply SCAMPER: Substitute, Combine, Adapt, Modify, Put to another use, Eliminate, Reverse. ' +
1690
+ 'For goal: ' + goal + '. What novel combination or modification of existing elements could work?'
1691
+ },
1692
+ {
1693
+ name: 'Analogy',
1694
+ prompt: 'By analogy: What similar problem has been solved in a completely different domain? ' +
1695
+ 'For goal: ' + goal + '. What approach from another field (biology, economics, gaming, logistics) transfers here?'
1696
+ },
1697
+ {
1698
+ name: 'First-Principles',
1699
+ prompt: 'First principles: Strip away all assumptions. What are the absolute basics of ' + goal + '? ' +
1700
+ 'What would you build if you had no prior art, no constraints, no legacy?'
1701
+ },
1702
+ {
1703
+ name: 'Random-Stimulus',
1704
+ prompt: 'Random stimulus: Pick an unrelated concept (a relay race, a restaurant menu, a river delta, a beehive). ' +
1705
+ 'How does it relate to ' + goal + '? What structural or procedural parallel exists?'
1706
+ },
1707
+ {
1708
+ name: 'Constraint-Inversion',
1709
+ prompt: 'Constraint inversion: Instead of ' + goal + ', what is the OPPOSITE goal? ' +
1710
+ 'How would you deliberately make things worse? Now invert the inversion — what does that reveal about the real solution?'
1711
+ }
1712
+ ]
1713
+
1714
+ const selectedStrategies = strategies.slice(0, numIdeas)
1715
+ const ideas = []
1716
+
1717
+ for (let i = 0; i < selectedStrategies.length; i++) {
1718
+ const s = selectedStrategies[i]
1719
+ const idea = {
1720
+ id: createId('idea'),
1721
+ title: 'Idea #' + (i + 1) + ' (' + s.name + '): ' + goal,
1722
+ description: 'Goal: ' + goal + '\n\n' +
1723
+ 'Strategy: ' + s.name + '\n\n' +
1724
+ 'Related Mio memory:\n' + relatedMemoryText + '\n\n' +
1725
+ (context ? 'Context: ' + context + '\n\n' : '') +
1726
+ (constraints.length > 0 ? 'Constraints:\n' + constraints.map(c => '- ' + c).join('\n') + '\n\n' : '') +
1727
+ 'Strategy prompt: ' + s.prompt + '\n\n' +
1728
+ 'Suggestion: Consider prototyping the idea and measuring its impact against prior decisions.',
1729
+ provenance: {
1730
+ strategy: s.name,
1731
+ relatedMemoryIds: relatedRecords.map(r => r.id).slice(0, 5),
1732
+ },
1733
+ generatedAt: new Date().toISOString(),
1734
+ goal,
1735
+ context: context || null,
1736
+ constraints,
1737
+ }
1738
+ ideas.push(idea)
1739
+ }
1740
+
1741
+ // Persist to ideas.jsonl
1742
+ for (const idea of ideas) {
1743
+ appendJsonl(ideasPath, idea)
1744
+ }
1745
+
1746
+ return { ideas, count: ideas.length, goal, strategies: ideas.map(i => i.provenance.strategy) }
1747
+ }
1748
+
1665
1749
  function listIdeas(args = {}) {
1666
1750
  if (!fs.existsSync(ideasPath)) return { ideas: [], count: 0, total: 0 }
1667
1751
  const now = Date.now()