- care:事件式關心(冷卻、每日上限、靜音、回覆中/輸入中不彈出),toast 與注入兩種輸出,台詞依觸發 × 個性 × 好感階段 - todo:新增、完成、承諾事項與到期提醒 - memory:檢索評分、遺忘曲線、鞏固與反思、金鑰過濾 - 以假時鐘與記憶體檔案系統測試核心接縫 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
73 lines
2.0 KiB
TypeScript
73 lines
2.0 KiB
TypeScript
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
|
|
},
|
|
}
|
|
}
|