feat(insights): add factual weekly and monthly reports

This commit is contained in:
Codex committed 2026-09-28 10:46:58 +09:00
1 parent 0d673a3b5a
commit 477e86f694
9 files changed
+138 -29

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ const meta = new URL("../dist/.openai/", import.meta.url);
await rm(dist, { recursive: true, force: true });
await Promise.all([mkdir(server, { recursive: true }), mkdir(meta, { recursive: true })]);
const [rawIndexHtml, addonsJs, bootGuardJs, i18nJs, tasksJs, calendarJs, i18nRenderersJs, manifest, serviceWorker, icon, localeEn, localeZh] = await Promise.all([text("index.html"), text("addons.js"), text("boot-guard.js"), text("i18n.js"), text("tasks.js"), text("calendar.js"), text("i18n-renderers.js"), text("manifest.webmanifest"), text("service-worker.js"), text("life-os-icon.svg"), readFile(new URL("../public/locales/en.json", import.meta.url), "utf8"), readFile(new URL("../public/locales/zh-CN.json", import.meta.url), "utf8")]);
const release = "1.5.8";
const release = "1.6.0";
const localeEnJs = `window.LifeOSLocales=window.LifeOSLocales||{};window.LifeOSLocales.en=${localeEn};`;
const localeZhJs = `window.LifeOSLocales=window.LifeOSLocales||{};window.LifeOSLocales['zh-CN']=${localeZh};`;
let indexHtml = rawIndexHtml.replace('src="addons.js"', `src="addons.js?v=${release}"`).replace('src="tasks.js"', `src="tasks.js?v=${release}"`).replace('src="calendar.js"', `src="calendar.js?v=${release}"`);
+37 -2
View File
@@ -115,14 +115,15 @@ assert.match(assets.i18nRenderersJs, /onclick=\"window\.setLanguage\('zh'\)\"/);
assert.doesNotMatch(assets.addonsJs, /lifeos_language_preference_v1/, "the device locale preference stays outside cloud-synced keys");
const uiNodes = new Map();
const uiNode = () => ({ innerHTML: "", textContent: "", style: {}, dataset: {}, classList: { add() {}, remove() {}, toggle() {}, contains: () => false }, remove() {}, append() {}, querySelector: () => null, querySelectorAll: () => [] });
for (const id of ["icons", "tasks", "launcher", "calendar", "desktop", "boot", "modal", "windows", "clock", "date", "desktop-brand", "life-launcher", "content-system"]) uiNodes.set(`#${id}`, uiNode());
for (const id of ["icons", "tasks", "launcher", "calendar", "desktop", "boot", "modal", "windows", "clock", "date", "desktop-brand", "life-launcher", "content-system", "content-insights"]) uiNodes.set(`#${id}`, uiNode());
const uiDocument = {
documentElement: { dataset: {}, lang: "en" }, title: "", head: { insertAdjacentHTML() {}, append() {} }, body: { append() {} },
querySelector: selector => uiNodes.get(selector) || null, getElementById: id => uiNodes.get(`#${id}`) || null,
createElement: uiNode, addEventListener() {}, querySelectorAll: () => []
};
const uiStorage = makeStorage();
const uiContext = vm.createContext({
document: uiDocument, navigator: { languages: ["en-US"], language: "en-US" }, localStorage: makeStorage(),
document: uiDocument, navigator: { languages: ["en-US"], language: "en-US" }, localStorage: uiStorage,
Blob, crypto: globalThis.crypto, innerWidth: 1000, innerHeight: 800,
matchMedia: () => ({ matches: false }), setTimeout: () => 0, setInterval: () => 0,
fetch: async () => ({ ok: false, json: async () => ({}) }), console,
@@ -143,6 +144,40 @@ uiContext.navigator.languages = ["zh-CN"];
uiContext.setLanguage("auto");
assert.match(uiNodes.get("#content-system").innerHTML, /系统设置/);
assert.equal(uiContext.LifeI18n.preference(), "auto");
uiContext.setLanguage("en");
const calendarKey = date => `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
const current = new Date(), previousWeek = new Date(current.getFullYear(), current.getMonth(), current.getDate() - 7, 12);
const currentKey = calendarKey(current), previousKey = calendarKey(previousWeek), currentStamp = new Date(current.getFullYear(), current.getMonth(), current.getDate(), 12).toISOString();
uiStorage.setItem("lifeos_memories", JSON.stringify([
{ id: "current-highlight", date: currentKey, title: "Current highlight", text: "A real saved moment", mood: "clear", energy: 4, tags: ["高光"] },
{ id: "previous-highlight", date: previousKey, title: "Previous highlight", text: "An older moment", mood: "rain", energy: 2, tags: [] }
]));
uiStorage.setItem("lifeos_museum", JSON.stringify([{ id: "artifact-prev", memoryId: "previous-highlight" }]));
uiStorage.setItem("lifeos_system", JSON.stringify({ schemaVersion: 2, tasksBoard: {
tasks: [{ id: "done-now", done: true, createdAt: currentStamp, completedAt: currentStamp }, { id: "done-before", done: true, createdAt: previousWeek.toISOString(), completedAt: previousWeek.toISOString() }],
goals: [{ id: "goal-now", done: true, completedAt: currentStamp }]
} }));
uiContext.insights(uiNodes.get("#content-insights"));
let report = uiNodes.get("#content-insights").innerHTML;
assert.match(report, /Current highlight/);
assert.doesNotMatch(report, /Previous highlight/);
assert.match(report, /1 tasks created · 1 goals completed/);
assert.match(report, /First entry|One energy entry/);
uiContext.shiftInsights(-1);
report = uiNodes.get("#content-insights").innerHTML;
assert.match(report, /Previous highlight/);
assert.doesNotMatch(report, /Current highlight/);
assert.match(report, /SAVED/);
uiContext.setInsightsView("month");
report = uiNodes.get("#content-insights").innerHTML;
assert.match(report, /Current highlight/);
assert.match(report, /MONTH/);
uiStorage.setItem("lifeos_memories", "[]");
uiStorage.setItem("lifeos_museum", "[]");
uiStorage.setItem("lifeos_system", JSON.stringify({ schemaVersion: 2, tasksBoard: { tasks: [], goals: [] } }));
uiContext.insights(uiNodes.get("#content-insights"));
assert.match(uiNodes.get("#content-insights").innerHTML, /No weather recorded in this period/);
assert.match(uiNodes.get("#content-insights").innerHTML, /No saved or tagged memories in this period/);
const zhLogin = await worker.default.fetch(new Request("https://life-os.test/", { headers: { "accept-language": "zh-CN,zh;q=0.9" } }), {});
assert.match(await zhLogin.text(), /登录 ChatGPT/);
const enLogin = await worker.default.fetch(new Request("https://life-os.test/", { headers: { "accept-language": "en-US,en;q=0.9" } }), {});