- 作息與疲勞、想念累積與時間感,主動發話沿用 care.ts 的冷卻、日限、靜音 - 想家與適應度(9.13) - 獨立腳本 fetch-materials.mjs 由系統排程寫入快取,hook 只讀、不連網 - 新增 /jsc-mod-companion:materials 與 setup location=、feeds= - 天氣微調心情基準,新聞依適應度每天最多 2 則並寫入情節記憶 - 版本 0.0.5 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
32 lines
1.5 KiB
TypeScript
32 lines
1.5 KiB
TypeScript
import { readJson } from './fs'
|
|
import type { Fs } from './fs'
|
|
import { MATERIALS as M, WEATHER_MOOD } from './rules'
|
|
|
|
// 外部素材快取:由系統排程執行的 scripts/fetch-materials.mjs 寫入,hook 只讀、不連網。
|
|
// 只存標題、摘要、連結與時間(at 為抓取時間,毫秒)。
|
|
export type Item = { title: string; summary: string; link: string; at: number }
|
|
export type Materials = { weather: Item | null; news: Item[] }
|
|
|
|
export const EMPTY: Materials = { weather: null, news: [] }
|
|
|
|
const isItem = (x: unknown): x is Item => {
|
|
const i = x as Item
|
|
return !!i && typeof i.title === 'string' && typeof i.summary === 'string' && typeof i.link === 'string' && typeof i.at === 'number'
|
|
}
|
|
|
|
/** 讀快取並丟掉過期項目:天氣 6 小時、新聞 24 小時;檔案缺失或壞掉就是沒查 */
|
|
export async function readMaterials(fs: Fs, path: string, now: number): Promise<Materials> {
|
|
const raw = await readJson<{ weather?: unknown; news?: unknown }>(fs, path)
|
|
if (!raw) return EMPTY
|
|
const weather = isItem(raw.weather) && now - raw.weather.at < M.weatherTtlMs ? raw.weather : null
|
|
const news = (Array.isArray(raw.news) ? raw.news : []).filter(isItem).filter(n => now - n.at < M.newsTtlMs)
|
|
return { weather, news }
|
|
}
|
|
|
|
/** 天氣對心情基準的微調;未知狀況為 0,且不超過上限 */
|
|
export function weatherShift(w: Item | null): number {
|
|
if (!w) return 0
|
|
const v = WEATHER_MOOD[w.title] ?? 0
|
|
return Math.max(-M.weatherCap, Math.min(M.weatherCap, v))
|
|
}
|