import type { Plugin, Hooks } from "@kirincode-ai/plugin" import { MemoryStore } from "./memory" import { SkillRegistry } from "./skills" import { handleMemoryCommand, handleSkillCommand } from "./commands" export const KirinCodePlugin: Plugin = async ({ client, project, directory, worktree, $ }) => { const store = new MemoryStore(worktree) const registry = new SkillRegistry() // Load skills at startup registry.load(worktree) // Load memory summary for context injection const memorySummary = store.loadSummary() return { // Inject memory + skills into system context "experimental.chat.system.transform": async (_input, output) => { const extras: string[] = [] if (memorySummary) { extras.push("## Your Memory (from past sessions)", memorySummary) } const skillCtx = registry.formatSystemContext() if (skillCtx) { extras.push(skillCtx) } if (extras.length) { output.system = [...output.system, ...extras] } }, // Handle /memory and /skill commands "command.execute.before": async (input, output) => { if (input.command === "memory") { output.parts = await handleMemoryCommand(input.arguments, store) } if (input.command === "skill") { output.parts = await handleSkillCommand(input.arguments, registry, worktree) } }, // Auto-memory on session idle event: async ({ event }) => { if (event.type === "session.idle") { const today = new Date().toISOString().slice(0, 10) store.updateIndex({ date: today, category: "session", summary: `Session completed in ${directory}`, tags: ["auto"], }) } }, // Preserve memory context across compaction "experimental.session.compacting": async (_input, output) => { const summary = store.loadSummary() if (summary) { output.context.push("## Persisted Memory\n" + summary) } }, // Shell env: expose KIRINCODE_ env vars "shell.env": async (_input, output) => { output.env.KIRINCODE_MEMORY_DIR = store["memoryDir"] }, } satisfies Hooks } export { MemoryStore, SkillRegistry }