opencode-config/.opencode/tools/memory-access.ts
Sergey 4cf149cb02
docs(memory): reindex + update SKILL.md (#104)
* feat(memory): add OPENAI_EMBEDDING_BATCH_DELAY support

* docs(memory): update SKILL.md for progressive enhancement and auto-setup

* docs(memory): update AGENTS.md tool usage policy

* docs(memory): fix stale snake_case tool references in skills, agents, tools

* docs(handoff): add handoff + ADR for reindex-skill-update

* docs(handoff): set PR number

* refactor(memory): extract _embed_in_batches to satisfy xenon rank A

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-27 02:08:35 +03:00

66 lines
No EOL
2.6 KiB
TypeScript

import fs from "fs"
import path from "path"
import { tool } from "@opencode-ai/plugin"
import { FRONTMATTER_RE, resolveMemoryDir } from "./_memory-shared"
function todayISO(): string {
return new Date().toISOString().slice(0, 10)
}
function bumpAccessFields(yaml: string, dateStr: string): { yaml: string; newCount: number } {
const countMatch = yaml.match(/^access_count:\s*(\d+)/m)
const currentCount = countMatch ? parseInt(countMatch[1], 10) : 0
const newCount = currentCount + 1
let updated = yaml
if (updated.match(/^last_accessed:/m)) {
updated = updated.replace(/^last_accessed:.*$/m, `last_accessed: ${dateStr}`)
} else {
updated += `\nlast_accessed: ${dateStr}`
}
if (updated.match(/^access_count:/m)) {
updated = updated.replace(/^access_count:.*$/m, `access_count: ${newCount}`)
} else {
updated += `\naccess_count: ${newCount}`
}
return { yaml: updated, newCount }
}
export default tool({
description:
"Record that a memory file was accessed (read and used). Updates last_accessed date and increments access_count in frontmatter. " +
"Call this AFTER reading a memory file that you actually used to inform your work — not for casual browsing. " +
"This helps the memory system track which memories are actively useful vs. stale. " +
"Atomic write (tmp + rename). Does NOT commit — the next memory-save will sync the change.",
args: {
path: tool.schema
.string()
.describe("Relative path within the memory directory (e.g. 'technical/build-tooling.md')"),
},
async execute(args) {
const memoryDir = resolveMemoryDir()
const filePath = path.join(memoryDir, args.path)
if (!fs.existsSync(filePath)) return `Could not update ${args.path} (file not found)`
let content: string
try {
content = fs.readFileSync(filePath, "utf-8")
} catch (e) {
process.stderr.write(`[memory-access] read failed ${args.path}: ${(e as Error).message}\n`)
return `Could not update ${args.path}`
}
const fmMatch = content.match(FRONTMATTER_RE)
if (!fmMatch) return `No frontmatter in ${args.path} — skipped`
const yaml = fmMatch[1]
const body = fmMatch[2]
const { yaml: updatedYaml, newCount } = bumpAccessFields(yaml, todayISO())
const newContent = `---\n${updatedYaml}\n---\n${body}`
try {
const tmp = filePath + ".tmp"
fs.writeFileSync(tmp, newContent, "utf-8")
fs.renameSync(tmp, filePath)
} catch (e) {
process.stderr.write(`[memory-access] write failed ${args.path}: ${(e as Error).message}\n`)
return `Could not update ${args.path}`
}
return `Accessed: ${args.path}, count=${newCount}`
},
})