Files
homeclaw/scripts/backfill-searxng-vacuum-facts.ts
T
kimandClaude Sonnet 5 571c684dad SearXNG 별칭·로봇청소기 IP 사실을 homeclaw RAG 메모리에 백필
시어엔진(SearXNG)/로봇청소기 IP가 Claude Code 자신의 프로젝트 메모리에만
있고 homeclaw 챗봇의 memory_write 경로에는 한 번도 안 들어갔던 걸 RAG
업그레이드 조사 중 발견. memory_write와 동일한 경로(USER.md + 벡터스토어)로
백필.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 15:33:59 +09:00

57 lines
2.6 KiB
TypeScript

// One-time backfill: two facts (SearXNG nickname, vacuum robot IPs) that turned out to
// exist only in Claude Code's own project memory (feedback_searxng_nickname.md,
// project_valetudo_vacuum.md) and had never actually been written into homeclaw's own
// memory_write/vector-store path — discovered 2026-08-06 while investigating why the RAG
// hybrid-search upgrade returned 0 hits for "SearXNG 별칭"/"로봇청소기 IP" queries (see
// project_vector_memory_chroma memory, "남은 과제" correction). Writes through the exact
// same path memory_write itself uses (USER.md append + addMemoryVector), not a shortcut,
// so these look native to anything reading either store.
import fs from 'fs';
import path from 'path';
import { addMemoryVector } from '../src/gateway/memory/memory-vector';
const WORKSPACE = '/srv/homeclaw/.smallclaw/users/papa/workspace';
const USER_MD_PATH = path.join(WORKSPACE, 'prompts', 'USER.md');
const CATEGORY = 'projects';
const FACTS = [
'SearXNG(로컬 메타서치 엔진, localhost:8888)의 별칭은 "시어엔진"이다.',
'로봇청소기 1호기(Xiaomi SDJQR01RR, Valetudo 설치됨)의 IP는 192.168.0.76이다.',
'로봇청소기 2호기(Xiaowa E202-01, Valetudo 미지원이라 python-miio로 로컬 제어)의 IP는 192.168.0.87이다.',
];
function appendToUserMd(content: string, date: string) {
let text = fs.readFileSync(USER_MD_PATH, 'utf-8');
const entry = `- ${content} [${date}]`;
const sectionHeader = `## ${CATEGORY}`;
const sectionIdx = text.indexOf(`\n${sectionHeader}`);
if (sectionIdx !== -1) {
const afterHeader = sectionIdx + sectionHeader.length + 1;
const nextSection = text.indexOf('\n## ', afterHeader);
const insertAt = nextSection !== -1 ? nextSection : text.length;
text = text.slice(0, insertAt) + '\n' + entry + text.slice(insertAt);
} else {
const closingComment = text.lastIndexOf('\n---');
const insertAt = closingComment !== -1 ? closingComment : text.length;
text = text.slice(0, insertAt) + '\n\n' + sectionHeader + '\n' + entry + text.slice(insertAt);
}
fs.writeFileSync(USER_MD_PATH, text, 'utf-8');
}
async function main() {
const date = new Date().toISOString().split('T')[0];
for (const fact of FACTS) {
appendToUserMd(fact, date);
await addMemoryVector({
id: `${WORKSPACE}:user:${CATEGORY}:${Date.now()}`,
text: fact,
metadata: { workspace: WORKSPACE, file: 'user', category: CATEGORY, date },
});
console.log('written:', fact);
await new Promise(r => setTimeout(r, 50)); // keep ids unique (Date.now() granularity)
}
console.log('done');
}
main().catch(e => { console.error(e); process.exit(1); });