* feat(memory): memory-save tool with auto-setup * feat(memory): memory-search with keyword and semantic fallback * feat(memory): memory-list and memory-access tools * feat(memory): memory-doctor diagnostic tool * docs(handoff): add handoff and ADR for ts memory tools * docs(handoff): set PR number * docs(handoff): finalize pr-101 frontmatter and pending * docs(project-map): add 5 memory TS tools after PR#101 * refactor(memory): extract shared helpers to _memory-shared.ts * refactor(memory): split oversized execute functions * fix(memory): handle git checkout and catch blocks --------- Co-authored-by: opencode-agent <agent@opencode.local>
65 lines
No EOL
2.4 KiB
TypeScript
65 lines
No EOL
2.4 KiB
TypeScript
import fs from "fs"
|
|
import path from "path"
|
|
import { tool } from "@opencode-ai/plugin"
|
|
import { CATEGORIES, parseFrontmatter, resolveMemoryDir, walkMd } from "./_memory-shared"
|
|
|
|
export default tool({
|
|
description:
|
|
"Browse memories in the memory directory. Without a category, lists all categories with file counts. " +
|
|
"With a category, lists files in that category with their summaries (parsed from frontmatter). " +
|
|
"Pure TS, no subprocess. Categories: preferences, repos, technical, people, workflows, snippets, notes.",
|
|
args: {
|
|
category: tool.schema
|
|
.string()
|
|
.optional()
|
|
.describe("Category to list: preferences, repos, technical, people, workflows, snippets, notes"),
|
|
},
|
|
async execute(args) {
|
|
const memoryDir = resolveMemoryDir()
|
|
if (!args.category) {
|
|
const lines = ["## Memory Categories\n"]
|
|
for (const cat of CATEGORIES) {
|
|
const catDir = path.join(memoryDir, cat)
|
|
const files = fs.existsSync(catDir) ? walkMd(catDir) : []
|
|
lines.push(`- **${cat}/** (${files.length} files)`)
|
|
}
|
|
return lines.join("\n")
|
|
}
|
|
const catDir = path.join(memoryDir, args.category)
|
|
if (!fs.existsSync(catDir)) return `Category not found: ${args.category}`
|
|
const absFiles = walkMd(catDir)
|
|
if (absFiles.length === 0) return `No memories in category: ${args.category}`
|
|
|
|
interface Row {
|
|
path: string
|
|
title: string
|
|
summary: string
|
|
importance: string
|
|
updated: string
|
|
}
|
|
const rows: Row[] = []
|
|
for (const abs of absFiles) {
|
|
try {
|
|
const content = fs.readFileSync(abs, "utf-8")
|
|
const meta = parseFrontmatter(content)
|
|
const rel = path.relative(catDir, abs)
|
|
rows.push({
|
|
path: `${args.category}/${rel}`,
|
|
title: meta.title || rel.replace(/\.md$/, ""),
|
|
summary: meta.summary || "",
|
|
importance: meta.importance || "medium",
|
|
updated: meta.updated || "",
|
|
})
|
|
} catch (e) {
|
|
process.stderr.write(`[memory-list] read failed ${abs}: ${(e as Error).message}\n`)
|
|
}
|
|
}
|
|
rows.sort((a, b) => (b.updated || "").localeCompare(a.updated || ""))
|
|
const lines = [`## ${args.category}/ (${rows.length} files)\n`]
|
|
for (const f of rows) {
|
|
lines.push(`- **${f.path}** [${f.importance}] ${f.updated ? `(${f.updated})` : ""}`)
|
|
if (f.summary) lines.push(` ${f.summary}`)
|
|
}
|
|
return lines.join("\n")
|
|
},
|
|
}) |