@miphamai/cli 0.6.5 → 0.6.6
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/package.json +1 -1
- package/src/index.tsx +18 -0
- package/src/plugin/plugin-loader.ts +85 -16
- package/src/ui/app.tsx +8 -4
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -9,9 +9,11 @@ import { QueryEngine } from './core/engine'
|
|
|
9
9
|
import { SessionStore } from './core/session-store'
|
|
10
10
|
import { SkillsLoader } from './skills/loader'
|
|
11
11
|
import { PluginManager } from './plugin/plugin-manager'
|
|
12
|
+
import { loadPlugins } from './plugin/plugin-loader'
|
|
12
13
|
import { createToolRegistry } from './tools'
|
|
13
14
|
import { McpClient } from './mcp/client'
|
|
14
15
|
import { registerMcpServerTools } from './mcp/registry'
|
|
16
|
+
import { AgentRegistry } from './agent/agent-registry'
|
|
15
17
|
import { HookEngine } from './core/hooks'
|
|
16
18
|
import { ArtifactServer } from './artifacts/server'
|
|
17
19
|
import { ARTIFACTS_DIR, ARTIFACT_PORT, MIPHAM_DIR } from './shared/constants'
|
|
@@ -142,6 +144,22 @@ export async function runApp(options: RunOptions): Promise<void> {
|
|
|
142
144
|
engine.setArtifactServer(artifactServer)
|
|
143
145
|
engine.setAgentViewManager(agentViewManager)
|
|
144
146
|
engine.setSkillsLoader(skillsLoader)
|
|
147
|
+
|
|
148
|
+
// Initialize agent registry and load plugin agents/skills/MCP/hooks
|
|
149
|
+
const agentRegistry = new AgentRegistry()
|
|
150
|
+
agentRegistry.loadUserAgents()
|
|
151
|
+
agentRegistry.loadProjectAgents(process.cwd())
|
|
152
|
+
engine.setAgentRegistry(agentRegistry)
|
|
153
|
+
|
|
154
|
+
loadPlugins(
|
|
155
|
+
pluginManager,
|
|
156
|
+
agentRegistry,
|
|
157
|
+
skillsLoader,
|
|
158
|
+
hookEngine,
|
|
159
|
+
McpClient.getInstance(),
|
|
160
|
+
tools,
|
|
161
|
+
)
|
|
162
|
+
|
|
145
163
|
engine.setupContextSummarizer()
|
|
146
164
|
|
|
147
165
|
// Auto-save session on exit
|
|
@@ -1,36 +1,105 @@
|
|
|
1
|
-
import type { PluginManager } from './plugin-manager'
|
|
2
1
|
import { join } from 'node:path'
|
|
3
|
-
import { existsSync } from 'node:fs'
|
|
2
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
3
|
+
import type { PluginManager } from './plugin-manager'
|
|
4
|
+
import type { AgentRegistry } from '../agent/agent-registry'
|
|
5
|
+
import type { SkillsLoader } from '../skills/loader'
|
|
6
|
+
import type { HookEngine } from '../core/hooks'
|
|
7
|
+
import type { McpClient } from '../mcp/client'
|
|
8
|
+
import { registerMcpServerTools } from '../mcp/registry'
|
|
9
|
+
import type { McpServerConfig, ToolDefinition, HookDefinition } from '../shared/types'
|
|
4
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Activate all enabled plugins — load their agents, skills, MCP servers, and hooks.
|
|
13
|
+
*
|
|
14
|
+
* Called once at startup after the core subsystems (agent registry, skills loader,
|
|
15
|
+
* hook engine, MCP client, tool registry) are initialized.
|
|
16
|
+
*/
|
|
5
17
|
export function loadPlugins(
|
|
6
18
|
pluginManager: PluginManager,
|
|
7
|
-
|
|
8
|
-
skillsLoader:
|
|
19
|
+
agentRegistry: AgentRegistry,
|
|
20
|
+
skillsLoader: SkillsLoader,
|
|
21
|
+
hookEngine: HookEngine,
|
|
22
|
+
mcpClient: McpClient,
|
|
23
|
+
toolsMap: Map<string, ToolDefinition>,
|
|
9
24
|
): void {
|
|
10
25
|
for (const plugin of pluginManager.getEnabled()) {
|
|
11
|
-
//
|
|
26
|
+
// ── Custom agents ──
|
|
12
27
|
const agentsDir = join(plugin.path, 'agents')
|
|
13
28
|
if (existsSync(agentsDir)) {
|
|
14
|
-
|
|
29
|
+
try {
|
|
30
|
+
agentRegistry.loadDirectory(agentsDir, 'user')
|
|
31
|
+
} catch (err) {
|
|
32
|
+
process.stderr.write(
|
|
33
|
+
`[plugin] Failed to load agents from "${plugin.name}": ${String(err)}\n`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
15
36
|
}
|
|
16
37
|
|
|
17
|
-
//
|
|
38
|
+
// ── Custom skills ──
|
|
18
39
|
const skillsDir = join(plugin.path, 'skills')
|
|
19
40
|
if (existsSync(skillsDir)) {
|
|
20
|
-
|
|
41
|
+
try {
|
|
42
|
+
skillsLoader.loadExternal([skillsDir])
|
|
43
|
+
} catch (err) {
|
|
44
|
+
process.stderr.write(
|
|
45
|
+
`[plugin] Failed to load skills from "${plugin.name}": ${String(err)}\n`,
|
|
46
|
+
)
|
|
47
|
+
}
|
|
21
48
|
}
|
|
22
49
|
|
|
23
|
-
//
|
|
50
|
+
// ── MCP servers ──
|
|
24
51
|
const mcpDir = join(plugin.path, 'mcp-servers')
|
|
25
52
|
if (existsSync(mcpDir)) {
|
|
26
|
-
|
|
53
|
+
try {
|
|
54
|
+
const entries = readdirSync(mcpDir)
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
if (!entry.endsWith('.json')) continue
|
|
57
|
+
try {
|
|
58
|
+
const raw = readFileSync(join(mcpDir, entry), 'utf-8')
|
|
59
|
+
const cfg = JSON.parse(raw) as McpServerConfig
|
|
60
|
+
if (cfg.name && cfg.command) {
|
|
61
|
+
mcpClient
|
|
62
|
+
.connect(cfg)
|
|
63
|
+
.then(() => {
|
|
64
|
+
const count = registerMcpServerTools(cfg.name, toolsMap)
|
|
65
|
+
if (count > 0) {
|
|
66
|
+
process.stderr.write(
|
|
67
|
+
`[plugin] "${plugin.name}": registered ${count} MCP tools from "${cfg.name}"\n`,
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
.catch((err: unknown) => {
|
|
72
|
+
process.stderr.write(
|
|
73
|
+
`[plugin] Failed to connect MCP "${cfg.name}" from "${plugin.name}": ${String(err)}\n`,
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
} catch {
|
|
78
|
+
// skip unparseable MCP config files
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
process.stderr.write(
|
|
83
|
+
`[plugin] Failed to load MCP configs from "${plugin.name}": ${String(err)}\n`,
|
|
84
|
+
)
|
|
85
|
+
}
|
|
27
86
|
}
|
|
28
87
|
|
|
29
|
-
//
|
|
30
|
-
|
|
88
|
+
// ── Hooks from plugin.json ──
|
|
89
|
+
try {
|
|
90
|
+
const manifestPath = join(plugin.path, 'plugin.json')
|
|
91
|
+
if (existsSync(manifestPath)) {
|
|
92
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'))
|
|
93
|
+
if (manifest.hooks && Array.isArray(manifest.hooks)) {
|
|
94
|
+
for (const hook of manifest.hooks as HookDefinition[]) {
|
|
95
|
+
if (hook.event) {
|
|
96
|
+
hookEngine.register(hook)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch (err) {
|
|
102
|
+
process.stderr.write(`[plugin] Failed to load hooks from "${plugin.name}": ${String(err)}\n`)
|
|
103
|
+
}
|
|
31
104
|
}
|
|
32
|
-
|
|
33
|
-
// Suppress unused parameter warnings — these are wiring stubs for future phases
|
|
34
|
-
void engine
|
|
35
|
-
void skillsLoader
|
|
36
105
|
}
|
package/src/ui/app.tsx
CHANGED
|
@@ -97,10 +97,14 @@ export function App({
|
|
|
97
97
|
|
|
98
98
|
// Initialize agent registry (one-time, on mount)
|
|
99
99
|
useMemo(() => {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
// Agent registry may already be initialized in index.tsx (for plugin loading).
|
|
101
|
+
// Only create a fresh one if not already set on the engine.
|
|
102
|
+
if (!engine.getAgentRegistry()) {
|
|
103
|
+
const agentRegistry = new AgentRegistry()
|
|
104
|
+
agentRegistry.loadUserAgents()
|
|
105
|
+
agentRegistry.loadProjectAgents(process.cwd())
|
|
106
|
+
engine.setAgentRegistry(agentRegistry)
|
|
107
|
+
}
|
|
104
108
|
}, [])
|
|
105
109
|
|
|
106
110
|
const mkCtx = useCallback(
|