mio-agent-runtime 0.2.0 → 0.2.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.
package/README.md CHANGED
@@ -22,6 +22,13 @@ mio --json status Machine-readable status
22
22
  mio --json agents Machine-readable agents
23
23
  ```
24
24
 
25
+ ## Host notes
26
+
27
+ - WorkBuddy uses `~/.workbuddy/mcp.json` and requires each custom MCP server to
28
+ be approved in `~/.workbuddy/mcp-approvals.json`. `mio install workbuddy`
29
+ writes both files. If WorkBuddy is already running, restart it once so it
30
+ reloads the approval file.
31
+
25
32
  ## MIO_HOME
26
33
 
27
34
  默认 `~/.mio-intelligence`,可通过环境变量 `MIO_HOME` 覆盖。
@@ -38,4 +45,4 @@ packages/mio-cli
38
45
  ├── server/
39
46
  │ └── mio-intelligence-mcp/index.js
40
47
  └── package.json
41
- ```
48
+ ```
package/adapters/codex.js CHANGED
@@ -14,7 +14,7 @@ function isInstalled() {
14
14
  return fs.readFileSync(target, 'utf8').includes('[mcp_servers.mio-intelligence]')
15
15
  }
16
16
 
17
- function install({ node, serverScript, home, workspace }) {
17
+ function install({ node, serverScript, home, workspace, project }) {
18
18
  const target = configPath()
19
19
  const backup = `${target}.bak-mio-${Date.now()}`
20
20
  if (isInstalled()) {
@@ -31,6 +31,7 @@ function install({ node, serverScript, home, workspace }) {
31
31
 
32
32
  const context = JSON.stringify({
33
33
  agentId: 'codex',
34
+ project: project || path.basename(workspace || process.cwd()),
34
35
  workspace: workspace || process.cwd(),
35
36
  sessionId: 'codex-session',
36
37
  })
@@ -23,7 +23,7 @@ function isInstalled() {
23
23
  return Boolean(config && config.mcp && config.mcp['mio-intelligence'])
24
24
  }
25
25
 
26
- function install({ node, serverScript, home, workspace }) {
26
+ function install({ node, serverScript, home, workspace, project }) {
27
27
  const target = configPath()
28
28
  if (isInstalled()) {
29
29
  return {
@@ -42,6 +42,7 @@ function install({ node, serverScript, home, workspace }) {
42
42
  const existingMcp = config.mcp && typeof config.mcp === 'object' ? config.mcp : {}
43
43
  const context = JSON.stringify({
44
44
  agentId: 'opencode',
45
+ project: project || path.basename(workspace || process.cwd()),
45
46
  workspace: workspace || process.cwd(),
46
47
  sessionId: 'opencode-session',
47
48
  })
@@ -3,13 +3,26 @@
3
3
  const fs = require('fs')
4
4
  const path = require('path')
5
5
  const os = require('os')
6
+ const crypto = require('crypto')
7
+
8
+ function configDir() {
9
+ return (
10
+ process.env.WORKBUDDY_CONFIG_DIR ||
11
+ process.env.CODEBUDDY_CONFIG_DIR ||
12
+ path.join(os.homedir(), '.workbuddy')
13
+ )
14
+ }
6
15
 
7
16
  function configPath() {
8
- return path.join(os.homedir(), '.workbuddy', 'mcp.json')
17
+ return path.join(configDir(), 'mcp.json')
9
18
  }
10
19
 
11
20
  function legacyConfigPath() {
12
- return path.join(os.homedir(), '.workbuddy', '.mcp.json')
21
+ return path.join(configDir(), '.mcp.json')
22
+ }
23
+
24
+ function approvalsPath() {
25
+ return path.join(configDir(), 'mcp-approvals.json')
13
26
  }
14
27
 
15
28
  function readJson(file) {
@@ -23,24 +36,41 @@ function readJson(file) {
23
36
 
24
37
  function isInstalled() {
25
38
  const config = readJson(configPath())
26
- return Boolean(config && config.mcpServers && config.mcpServers['mio-intelligence'])
39
+ const entry = config && config.mcpServers && config.mcpServers['mio-intelligence']
40
+ if (!entry) return false
41
+
42
+ const approvals = readJson(approvalsPath()) || {}
43
+ return Boolean(approvals[approvalKey('mio-intelligence', entry)])
27
44
  }
28
45
 
29
- function install({ node, serverScript, home, workspace }) {
30
- const target = configPath()
31
- if (isInstalled()) {
32
- return {
33
- changed: false,
34
- configPath: target,
35
- message: 'WorkBuddy Mio MCP already installed.',
46
+ function approvalKey(name, entry) {
47
+ let input
48
+ if (entry.command) {
49
+ input = `${entry.command || ''}|${(entry.args || []).map(String).sort().join(',')}|${Object.keys(entry.env || {}).sort().join(',')}`
50
+ } else if (entry.url) {
51
+ try {
52
+ input = new URL(entry.url).origin
53
+ } catch (_) {
54
+ input = entry.url
36
55
  }
56
+ } else {
57
+ input = JSON.stringify(entry)
37
58
  }
38
59
 
39
- const backup = `${target}.bak-mio-${Date.now()}`
40
- if (fs.existsSync(target)) {
41
- fs.copyFileSync(target, backup)
42
- }
60
+ const hash = crypto.createHash('sha256').update(input).digest('hex')
61
+ return `${hash}::${name}`
62
+ }
43
63
 
64
+ function writeApproval(name, entry) {
65
+ const target = approvalsPath()
66
+ const approvals = readJson(target) || {}
67
+ approvals[approvalKey(name, entry)] = Date.now()
68
+ fs.mkdirSync(path.dirname(target), { recursive: true })
69
+ fs.writeFileSync(target, `${JSON.stringify(approvals, null, 2)}\n`, 'utf8')
70
+ }
71
+
72
+ function install({ node, serverScript, home, workspace, project }) {
73
+ const target = configPath()
44
74
  const canonical = readJson(target) || {}
45
75
  const legacy = readJson(legacyConfigPath()) || {}
46
76
  const canonicalServers =
@@ -59,6 +89,7 @@ function install({ node, serverScript, home, workspace }) {
59
89
 
60
90
  const context = JSON.stringify({
61
91
  agentId: 'workbuddy',
92
+ project: project || path.basename(workspace || process.cwd()),
62
93
  workspace: workspace || process.cwd(),
63
94
  sessionId: 'workbuddy-session',
64
95
  })
@@ -66,7 +97,6 @@ function install({ node, serverScript, home, workspace }) {
66
97
  config.mcpServers = {
67
98
  ...config.mcpServers,
68
99
  'mio-intelligence': {
69
- type: 'stdio',
70
100
  command: node,
71
101
  args: [serverScript],
72
102
  env: {
@@ -76,15 +106,23 @@ function install({ node, serverScript, home, workspace }) {
76
106
  },
77
107
  }
78
108
 
109
+ writeApproval('mio-intelligence', config.mcpServers['mio-intelligence'])
110
+
111
+ const backup = `${target}.bak-mio-${Date.now()}`
112
+ if (fs.existsSync(target)) {
113
+ fs.copyFileSync(target, backup)
114
+ }
115
+
79
116
  fs.mkdirSync(path.dirname(target), { recursive: true })
80
117
  fs.writeFileSync(target, `${JSON.stringify(config, null, 2)}\n`, 'utf8')
81
118
 
82
119
  return {
83
120
  changed: true,
84
121
  configPath: target,
122
+ approvalsPath: approvalsPath(),
85
123
  backup,
86
- message: 'WorkBuddy Mio MCP installed. Restart WorkBuddy to load it.',
124
+ message: 'WorkBuddy Mio MCP installed and approved. WorkBuddy should auto-load it; restart if it was already running.',
87
125
  }
88
126
  }
89
127
 
90
- module.exports = { configPath, isInstalled, install }
128
+ module.exports = { configDir, configPath, approvalsPath, approvalKey, isInstalled, install }
package/bin/mio.js CHANGED
@@ -4,6 +4,7 @@
4
4
  const fs = require('fs')
5
5
  const path = require('path')
6
6
  const os = require('os')
7
+ const { execFileSync } = require('child_process')
7
8
 
8
9
  const SERVER_SCRIPT = path.resolve(__dirname, '..', 'server', 'mio-intelligence-mcp', 'index.js')
9
10
  const MIO_HOME = process.env.MIO_HOME || path.join(os.homedir(), '.mio-intelligence')
@@ -15,6 +16,23 @@ const adapters = {
15
16
  workbuddy: require('../adapters/workbuddy.js'),
16
17
  }
17
18
 
19
+ function projectFromWorkspace(workspace) {
20
+ try {
21
+ const commonDir = execFileSync(
22
+ 'git',
23
+ ['-C', workspace, 'rev-parse', '--path-format=absolute', '--git-common-dir'],
24
+ { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }
25
+ ).trim()
26
+ if (commonDir) {
27
+ const name = path.basename(path.dirname(commonDir))
28
+ if (name) return name
29
+ }
30
+ } catch (_) {
31
+ // fall through to workspace basename
32
+ }
33
+ return path.basename(workspace)
34
+ }
35
+
18
36
  function ensureHome() {
19
37
  fs.mkdirSync(MIO_HOME, { recursive: true })
20
38
  fs.mkdirSync(path.join(MIO_HOME, 'logs'), { recursive: true })
@@ -117,6 +135,7 @@ function installCommand(host, useJson) {
117
135
  serverScript: SERVER_SCRIPT,
118
136
  home: MIO_HOME,
119
137
  workspace: process.cwd(),
138
+ project: projectFromWorkspace(process.cwd()),
120
139
  })
121
140
  } catch (error) {
122
141
  console.error(`Failed to install ${host}: ${error.message || error}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mio-agent-runtime",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Mio Agent Runtime installer and MCP intelligence layer",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",