feat: M4 主動關心、待辦與記憶鞏固核心模組
- care:事件式關心(冷卻、每日上限、靜音、回覆中/輸入中不彈出),toast 與注入兩種輸出,台詞依觸發 × 個性 × 好感階段 - todo:新增、完成、承諾事項與到期提醒 - memory:檢索評分、遺忘曲線、鞏固與反思、金鑰過濾 - 以假時鐘與記憶體檔案系統測試核心接縫 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
// 檔案系統與時鐘由外部注入,核心不直接碰真實環境
|
||||
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)
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user