Files
jsc-marketplace/plugins/jsc-mod-companion/hooks/companion/todo.ts
T
rootandClaude Sonnet 5.5 ea17f1cb2d refactor: jsc-mod 改名 jsc-mod-statusline、jsc-companion 改名 jsc-mod-companion,指令拆成獨立指令
- jsc-mod-statusline:/jsc-mod-statusline:enable、compact、disable
- jsc-mod-companion:/jsc-mod-companion:status、switch、disable、setup、todo、quiet
- 同步更新 plugin.json、marketplace.json 與各 README
- 補上 statusline band 測試缺少的 ui.render 底層處理

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 05:45:52 +00:00

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
},
}
}