feat: M4 主動關心、待辦與記憶鞏固核心模組
- care:事件式關心(冷卻、每日上限、靜音、回覆中/輸入中不彈出),toast 與注入兩種輸出,台詞依觸發 × 個性 × 好感階段 - todo:新增、完成、承諾事項與到期提醒 - memory:檢索評分、遺忘曲線、鞏固與反思、金鑰過濾 - 以假時鐘與記憶體檔案系統測試核心接縫 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import type { Clock, Fs } from './io'
|
||||
import { readJson, writeJson } from './io'
|
||||
|
||||
export interface Todo {
|
||||
id: number
|
||||
title: string
|
||||
done: boolean
|
||||
/** 承諾事項:助理答應記住的事 */
|
||||
promise: boolean
|
||||
dueAt?: number
|
||||
createdAt: number
|
||||
doneAt?: number
|
||||
/** 已提醒過,避免重複 */
|
||||
reminded?: boolean
|
||||
}
|
||||
|
||||
export interface TodoList {
|
||||
add(title: string, opts?: { promise?: boolean; dueAt?: number }): Promise<Todo>
|
||||
complete(id: number): Promise<Todo | null>
|
||||
list(opts?: { all?: boolean }): Promise<Todo[]>
|
||||
/** 角色行顯示的待辦數(未完成) */
|
||||
open(): Promise<number>
|
||||
/** 取出到期且尚未提醒的項目,並標記為已提醒 */
|
||||
due(): Promise<Todo[]>
|
||||
}
|
||||
|
||||
export function createTodos(fs: Fs, clock: Clock, path: string): TodoList {
|
||||
const load = () => readJson<Todo[]>(fs, path, [])
|
||||
const save = (t: Todo[]) => writeJson(fs, path, t)
|
||||
return {
|
||||
async add(title, opts = {}) {
|
||||
const all = await load()
|
||||
const t: Todo = {
|
||||
id: all.reduce((m, x) => Math.max(m, x.id), 0) + 1,
|
||||
title: title.trim(),
|
||||
done: false,
|
||||
promise: !!opts.promise,
|
||||
dueAt: opts.dueAt,
|
||||
createdAt: clock(),
|
||||
}
|
||||
all.push(t)
|
||||
await save(all)
|
||||
return t
|
||||
},
|
||||
async complete(id) {
|
||||
const all = await load()
|
||||
const t = all.find(x => x.id === id)
|
||||
if (!t || t.done) return t ?? null
|
||||
t.done = true
|
||||
t.doneAt = clock()
|
||||
await save(all)
|
||||
return t
|
||||
},
|
||||
async list(opts = {}) {
|
||||
const all = await load()
|
||||
return opts.all ? all : all.filter(t => !t.done)
|
||||
},
|
||||
async open() {
|
||||
return (await load()).filter(t => !t.done).length
|
||||
},
|
||||
async due() {
|
||||
const all = await load()
|
||||
const now = clock()
|
||||
const hit = all.filter(t => !t.done && !t.reminded && t.dueAt !== undefined && t.dueAt <= now)
|
||||
if (hit.length) {
|
||||
for (const t of hit) t.reminded = true
|
||||
await save(all)
|
||||
}
|
||||
return hit
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user