mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-25 00:27:32 +00:00
* feat: support plugin-contributed custom agents * fix: await plugin loading before agent catalog * fix: refresh plugin agents on v1 reload * test(agent-core-v2): add enabledSystemPrompts to the plugin service stub
207 lines
6.2 KiB
TypeScript
207 lines
6.2 KiB
TypeScript
/**
|
|
* `pluginService` — plugin management and consumption. Mirrors
|
|
* `agent-core-v2/app/plugin/plugin.ts` and `agent-core-v2/app/plugin/types.ts`;
|
|
* nested `McpServerConfig` mirrors `agent-core-v2/agent/mcp/config-schema.ts`,
|
|
* `HookDefConfig` mirrors `agent-core-v2/agent/externalHooks/configSection.ts`.
|
|
* `pluginSkillRoots`, `enabledSessionStarts`, `enabledSystemPrompts`,
|
|
* `enabledMcpServers`, and `enabledHooks` are excluded (not part of the
|
|
* klient wire surface).
|
|
*/
|
|
|
|
import { z } from 'zod';
|
|
|
|
import { noResult } from '../helpers.js';
|
|
import { mcpServerConfigSchema } from '../mcp.js';
|
|
import type { ServiceContract } from '../types.js';
|
|
|
|
export const pluginDiagnosticSchema = z.object({
|
|
severity: z.enum(['error', 'warn', 'info']),
|
|
message: z.string(),
|
|
});
|
|
|
|
const pluginAuthorSchema = z.object({
|
|
name: z.string().optional(),
|
|
email: z.string().optional(),
|
|
});
|
|
|
|
const pluginSessionStartSchema = z.object({
|
|
skill: z.string(),
|
|
});
|
|
|
|
const pluginInterfaceSchema = z.object({
|
|
displayName: z.string().optional(),
|
|
shortDescription: z.string().optional(),
|
|
longDescription: z.string().optional(),
|
|
developerName: z.string().optional(),
|
|
websiteURL: z.string().optional(),
|
|
});
|
|
|
|
const hookDefSchema = z.object({
|
|
event: z.enum([
|
|
'PreToolUse',
|
|
'PostToolUse',
|
|
'PostToolUseFailure',
|
|
'PermissionRequest',
|
|
'PermissionResult',
|
|
'UserPromptSubmit',
|
|
'Stop',
|
|
'StopFailure',
|
|
'Interrupt',
|
|
'SessionStart',
|
|
'SessionEnd',
|
|
'SubagentStart',
|
|
'SubagentStop',
|
|
'PreCompact',
|
|
'PostCompact',
|
|
'Notification',
|
|
]),
|
|
matcher: z.string().optional(),
|
|
command: z.string().min(1),
|
|
timeout: z.number().int().min(1).max(600).optional(),
|
|
});
|
|
|
|
const pluginCommandEntrySchema = z.object({
|
|
path: z.string(),
|
|
name: z.string(),
|
|
});
|
|
|
|
const pluginManifestKindSchema = z.enum(['kimi-plugin-root', 'kimi-plugin-dir']);
|
|
|
|
const pluginSourceSchema = z.enum(['local-path', 'zip-url', 'github']);
|
|
|
|
const pluginStateSchema = z.enum(['ok', 'error']);
|
|
|
|
const pluginGithubRefSchema = z.object({
|
|
kind: z.enum(['branch', 'tag', 'sha']),
|
|
value: z.string(),
|
|
});
|
|
|
|
export const pluginManifestSchema = z.object({
|
|
name: z.string(),
|
|
version: z.string().optional(),
|
|
description: z.string().optional(),
|
|
keywords: z.array(z.string()).optional(),
|
|
author: pluginAuthorSchema.optional(),
|
|
homepage: z.string().optional(),
|
|
license: z.string().optional(),
|
|
skills: z.array(z.string()).optional(),
|
|
agents: z.array(z.string()).optional(),
|
|
sessionStart: pluginSessionStartSchema.optional(),
|
|
mcpServers: z.record(z.string(), mcpServerConfigSchema).optional(),
|
|
hooks: z.array(hookDefSchema).optional(),
|
|
commands: z.array(pluginCommandEntrySchema).optional(),
|
|
interface: pluginInterfaceSchema.optional(),
|
|
skillInstructions: z.string().optional(),
|
|
systemPrompt: z.string().optional(),
|
|
});
|
|
|
|
export const pluginMcpServerInfoSchema = z.object({
|
|
name: z.string(),
|
|
runtimeName: z.string(),
|
|
enabled: z.boolean(),
|
|
transport: z.enum(['stdio', 'http', 'sse']),
|
|
command: z.string().optional(),
|
|
args: z.array(z.string()).optional(),
|
|
cwd: z.string().optional(),
|
|
url: z.string().optional(),
|
|
envKeys: z.array(z.string()).optional(),
|
|
headerKeys: z.array(z.string()).optional(),
|
|
});
|
|
|
|
export const pluginGithubMetadataSchema = z.object({
|
|
owner: z.string(),
|
|
repo: z.string(),
|
|
ref: pluginGithubRefSchema,
|
|
installedSha: z.string().optional(),
|
|
});
|
|
|
|
export const pluginSummarySchema = z.object({
|
|
id: z.string(),
|
|
displayName: z.string(),
|
|
version: z.string().optional(),
|
|
enabled: z.boolean(),
|
|
state: pluginStateSchema,
|
|
skillCount: z.number(),
|
|
mcpServerCount: z.number(),
|
|
enabledMcpServerCount: z.number(),
|
|
hookCount: z.number(),
|
|
commandCount: z.number(),
|
|
hasErrors: z.boolean(),
|
|
source: pluginSourceSchema,
|
|
originalSource: z.string().optional(),
|
|
github: pluginGithubMetadataSchema.optional(),
|
|
});
|
|
|
|
export const pluginInfoSchema = pluginSummarySchema.extend({
|
|
root: z.string(),
|
|
installedAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
manifestKind: pluginManifestKindSchema.optional(),
|
|
manifestPath: z.string().optional(),
|
|
manifest: pluginManifestSchema.optional(),
|
|
mcpServers: z.array(pluginMcpServerInfoSchema),
|
|
shadowedManifestPath: z.string().optional(),
|
|
diagnostics: z.array(pluginDiagnosticSchema),
|
|
});
|
|
|
|
/** Same shape as `reloadSummarySchema` in `./events.js` — keep in sync. */
|
|
export const reloadSummarySchema = z.object({
|
|
added: z.array(z.string()),
|
|
removed: z.array(z.string()),
|
|
errors: z.array(z.object({ id: z.string(), message: z.string() })),
|
|
});
|
|
|
|
export const pluginUpdateStatusSchema = z.object({
|
|
id: z.string(),
|
|
source: pluginSourceSchema,
|
|
current: pluginGithubRefSchema.optional(),
|
|
latest: pluginGithubRefSchema,
|
|
displayVersion: z.string(),
|
|
updateAvailable: z.boolean(),
|
|
});
|
|
|
|
export const pluginCommandDefSchema = z.object({
|
|
pluginId: z.string(),
|
|
name: z.string(),
|
|
description: z.string(),
|
|
body: z.string(),
|
|
path: z.string(),
|
|
});
|
|
|
|
export const installPluginInputSchema = z.object({
|
|
source: z.string(),
|
|
});
|
|
|
|
export const setPluginEnabledInputSchema = z.object({
|
|
id: z.string(),
|
|
enabled: z.boolean(),
|
|
});
|
|
|
|
export const setPluginMcpServerEnabledInputSchema = z.object({
|
|
id: z.string(),
|
|
server: z.string(),
|
|
enabled: z.boolean(),
|
|
});
|
|
|
|
export const removePluginInputSchema = z.object({
|
|
id: z.string(),
|
|
});
|
|
|
|
export const getPluginInfoInputSchema = z.object({
|
|
id: z.string(),
|
|
});
|
|
|
|
export const pluginsContract = {
|
|
listPlugins: { input: z.tuple([]), output: z.array(pluginSummarySchema) },
|
|
installPlugin: { input: z.tuple([installPluginInputSchema]), output: pluginSummarySchema },
|
|
setPluginEnabled: { input: z.tuple([setPluginEnabledInputSchema]), output: noResult },
|
|
setPluginMcpServerEnabled: {
|
|
input: z.tuple([setPluginMcpServerEnabledInputSchema]),
|
|
output: noResult,
|
|
},
|
|
removePlugin: { input: z.tuple([removePluginInputSchema]), output: noResult },
|
|
reloadPlugins: { input: z.tuple([]), output: reloadSummarySchema },
|
|
getPluginInfo: { input: z.tuple([getPluginInfoInputSchema]), output: pluginInfoSchema },
|
|
listPluginCommands: { input: z.tuple([]), output: z.array(pluginCommandDefSchema) },
|
|
checkUpdates: { input: z.tuple([]), output: z.array(pluginUpdateStatusSchema) },
|
|
} satisfies ServiceContract;
|