import type { Part } from "@kirincode-ai/sdk" import type { MemoryStore } from "./memory" import type { SkillRegistry } from "./skills" let partSeq = 0 function textPart(text: string, sessionID: string): Part { const id = `kc_part_${Date.now()}_${partSeq++}` return { id, sessionID, messageID: id, type: "text", text } } export async function handleMemoryCommand(args: string, store: MemoryStore, sessionID: string): Promise { const sub = args.trim() if (!sub || sub === "list") { return [textPart(store.format(), sessionID)] } if (sub.startsWith("read ")) { const topic = sub.slice(5).trim() const content = store.readTopic(topic) return [textPart(content || `No topic '${topic}' found. Topics: ${store.listTopics().join(", ") || "none"}`, sessionID)] } if (sub.startsWith("write ")) { const rest = sub.slice(6).trim() const spaceIdx = rest.indexOf(" ") if (spaceIdx === -1) return [textPart("Usage: /memory write ", sessionID)] const topic = rest.slice(0, spaceIdx) const content = rest.slice(spaceIdx + 1) store.writeTopic(topic, content) return [textPart(`Topic '${topic}' saved.`, sessionID)] } return [textPart("Usage: /memory [list|read |write ]", sessionID)] } export async function handleSkillCommand(args: string, registry: SkillRegistry, worktree: string, sessionID: string): Promise { const sub = args.trim() if (!sub || sub === "list") { const skills = registry.list() if (skills.length === 0) return [textPart("No skills registered. Use `/skill create ` to create one.", sessionID)] const lines = skills.map((s) => `- **/${s.manifest.name}** [${s.scope}] — ${s.manifest.description}`) return [textPart(lines.join("\n"), sessionID)] } if (sub.startsWith("create ")) { const rest = sub.slice(7).trim() const firstQuote = rest.match(/["'](.+?)["']/) if (firstQuote) { const name = firstQuote[1] ?? "" if (!name) return [textPart("Could not parse skill name from quoted string.", sessionID)] const desc = rest.slice((firstQuote[0] ?? "").length).trim().replace(/^["'](.+?)["']/, "$1") const path = registry.createSkill(name, desc, `# ${name}\n\nTODO: Write skill instructions here.`, "project", worktree) registry.load(worktree) return [textPart(`Skill '/${name}' created at ${path}\nEdit the file to add instructions, then use /skill ${name} to invoke.`, sessionID)] } const parts = rest.split(/\s+/) if (parts.length < 2) return [textPart("Usage: /skill create ", sessionID)] const name = parts[0] ?? "" if (!name) return [textPart("Usage: /skill create ", sessionID)] const desc = parts.slice(1).join(" ") const path = registry.createSkill(name, desc, `# ${name}\n\nTODO: Write skill instructions here.`, "project", worktree) registry.load(worktree) return [textPart(`Skill '/${name}' created at ${path}`, sessionID)] } if (sub === "reload") { registry.load(worktree) return [textPart(`Skills reloaded. ${registry.list().length} skill(s) available.`, sessionID)] } // Treat as skill name invocation const content = registry.injectSkill(sub) return [textPart(content, sessionID)] }