- care:事件式關心(冷卻、每日上限、靜音、回覆中/輸入中不彈出),toast 與注入兩種輸出,台詞依觸發 × 個性 × 好感階段 - todo:新增、完成、承諾事項與到期提醒 - memory:檢索評分、遺忘曲線、鞏固與反思、金鑰過濾 - 以假時鐘與記憶體檔案系統測試核心接縫 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
54 lines
1.3 KiB
TypeScript
54 lines
1.3 KiB
TypeScript
// 檔案系統與時鐘由外部注入,核心不直接碰真實環境
|
|
export interface Fs {
|
|
read(path: string): Promise<string | null>
|
|
/** 原子寫入:先寫暫存檔再改名 */
|
|
write(path: string, data: string): Promise<void>
|
|
}
|
|
|
|
export type Clock = () => number
|
|
|
|
export function memoryFs(): Fs & { files: Map<string, string> } {
|
|
const files = new Map<string, string>()
|
|
return {
|
|
files,
|
|
async read(p) {
|
|
return files.get(p) ?? null
|
|
},
|
|
async write(p, d) {
|
|
files.set(p, d)
|
|
},
|
|
}
|
|
}
|
|
|
|
export async function readJson<T>(fs: Fs, path: string, fallback: T): Promise<T> {
|
|
const raw = await fs.read(path)
|
|
if (raw === null) return fallback
|
|
try {
|
|
return JSON.parse(raw) as T
|
|
} catch {
|
|
return fallback
|
|
}
|
|
}
|
|
|
|
export const writeJson = (fs: Fs, path: string, value: unknown) => fs.write(path, JSON.stringify(value, null, 2))
|
|
|
|
export async function nodeFs(): Promise<Fs> {
|
|
const { readFile, writeFile, rename, mkdir } = await import('node:fs/promises')
|
|
const { dirname } = await import('node:path')
|
|
return {
|
|
async read(p) {
|
|
try {
|
|
return await readFile(p, 'utf8')
|
|
} catch {
|
|
return null
|
|
}
|
|
},
|
|
async write(p, d) {
|
|
await mkdir(dirname(p), { recursive: true })
|
|
const tmp = `${p}.${process.pid}.tmp`
|
|
await writeFile(tmp, d)
|
|
await rename(tmp, p)
|
|
},
|
|
}
|
|
}
|