cortico-world-hands 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +240 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25,6 +25,8 @@ var HANDS_DEFAULTS = {
|
|
|
25
25
|
hookGrams: "three",
|
|
26
26
|
skinPackUrl: "",
|
|
27
27
|
qqOwner: "",
|
|
28
|
+
ritualMorning: "08:00",
|
|
29
|
+
ritualNight: "23:00",
|
|
28
30
|
mediaKeepDays: 1,
|
|
29
31
|
mediaCleanHour: 4,
|
|
30
32
|
mediaMaxMB: 0
|
|
@@ -1801,6 +1803,85 @@ var HANDS_TOOL_DECLS = [
|
|
|
1801
1803
|
tags: ["flow"],
|
|
1802
1804
|
description: "\u7ACB\u523B\u505C\u624B\uFF1A\u4E00\u5206\u949F\u4E4B\u5185\u4E0D\u518D\u52A8\u4EFB\u4F55\u4E00\u4E0B\uFF08\u5DF2\u7ECF\u53D1\u51FA\u7684\u4E0D\u7B97\uFF09\u3002\u5BF9\u65B9\u8BF4\u300C\u522B\u52A8\u4E86\u300D\u300C\u505C\u4E0B\u300D\u6216\u8005\u4F60\u53D1\u73B0\u81EA\u5DF1\u70B9\u9519\u5730\u65B9\u65F6\u7528\u5B83\u3002",
|
|
1803
1805
|
parameters: { type: "object", properties: {}, required: [] }
|
|
1806
|
+
},
|
|
1807
|
+
{
|
|
1808
|
+
name: "agenda_add",
|
|
1809
|
+
tags: ["act"],
|
|
1810
|
+
description: '\u8BB0\u4E00\u6761\u65E5\u7A0B\uFF08\u5230\u70B9\u4F1A\u53EB\u9192\u5979\u4E00\u6B21\uFF09\u3002at \u7528 "2026-10-26 08:30" \u6216 "08:30"\uFF08\u4ECA\u5929/\u660E\u5929\u81EA\u52A8\u5224\u65AD\uFF09\u3002',
|
|
1811
|
+
parameters: {
|
|
1812
|
+
type: "object",
|
|
1813
|
+
properties: {
|
|
1814
|
+
title: { type: "string", description: "\u8981\u505A\u4EC0\u4E48" },
|
|
1815
|
+
at: { type: "string", description: '\u4EC0\u4E48\u65F6\u5019\uFF0C\u4F8B\u5982 "2026-10-26 08:30" \u6216 "20:30"' },
|
|
1816
|
+
who: { type: "string", description: "\u8C01\u8981\u6C42\u7684\uFF0C\u9ED8\u8BA4\u4E3B\u4EBA" }
|
|
1817
|
+
},
|
|
1818
|
+
required: ["title"]
|
|
1819
|
+
}
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
name: "agenda_list",
|
|
1823
|
+
tags: ["read"],
|
|
1824
|
+
description: "\u770B\u8FD8\u6CA1\u505A\u7684\u65E5\u7A0B\u3002",
|
|
1825
|
+
parameters: { type: "object", properties: {} }
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
name: "agenda_done",
|
|
1829
|
+
tags: ["act"],
|
|
1830
|
+
description: "\u628A\u4E00\u6761\u65E5\u7A0B\u6807\u8BB0\u5B8C\u6210\u3002",
|
|
1831
|
+
parameters: {
|
|
1832
|
+
type: "object",
|
|
1833
|
+
properties: { id: { type: "string", description: "agenda_list \u91CC\u7684 id" } },
|
|
1834
|
+
required: ["id"]
|
|
1835
|
+
}
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
name: "affinity_get",
|
|
1839
|
+
tags: ["read"],
|
|
1840
|
+
description: "\u67E5\u67D0\u4E2A\u4EBA\uFF08QQ \u53F7\uFF09\u5728\u5979\u5FC3\u91CC\u7684\u5206\u6570\u3001\u6863\u4F4D\u3001\u8BE5\u7528\u4EC0\u4E48\u6001\u5EA6\u3002",
|
|
1841
|
+
parameters: {
|
|
1842
|
+
type: "object",
|
|
1843
|
+
properties: { qq: { type: "string", description: "\u5BF9\u65B9\u7684 QQ \u53F7\u6216\u540D\u5B57" } },
|
|
1844
|
+
required: ["qq"]
|
|
1845
|
+
}
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
name: "affinity_adjust",
|
|
1849
|
+
tags: ["act"],
|
|
1850
|
+
description: "\u7ED9\u67D0\u4E2A\u4EBA\u8BB0\u4E00\u7B14\u5173\u7CFB\u53D8\u5316\uFF08\u53EF\u6B63\u53EF\u8D1F\uFF09\uFF0C\u5E76\u5199\u4E00\u53E5\u4E3A\u4EC0\u4E48\u3002",
|
|
1851
|
+
parameters: {
|
|
1852
|
+
type: "object",
|
|
1853
|
+
properties: {
|
|
1854
|
+
qq: { type: "string", description: "\u5BF9\u65B9\u7684 QQ \u53F7\u6216\u540D\u5B57" },
|
|
1855
|
+
delta: { type: "number", description: "\u53D8\u5316\u91CF\uFF0C\u6BD4\u5982 5 \u6216 -3" },
|
|
1856
|
+
why: { type: "string", description: "\u4E3A\u4EC0\u4E48" }
|
|
1857
|
+
},
|
|
1858
|
+
required: ["qq", "delta"]
|
|
1859
|
+
}
|
|
1860
|
+
},
|
|
1861
|
+
{
|
|
1862
|
+
name: "affinity_list",
|
|
1863
|
+
tags: ["read"],
|
|
1864
|
+
description: "\u770B\u5979\u5FC3\u91CC\u6392\u524D\u9762\u7684\u51E0\u4E2A\u4EBA\uFF0C\u8FDE\u540C\u5206\u6570\u548C\u6863\u4F4D\u3002",
|
|
1865
|
+
parameters: { type: "object", properties: {} }
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
name: "ritual_set",
|
|
1869
|
+
tags: ["act"],
|
|
1870
|
+
description: "\u8BB0\u4E00\u4E2A\u7EAA\u5FF5\u65E5\uFF08\u6708-\u65E5\uFF09\u3002\u5230\u70B9\u4F1A\u63D0\u9192\u4E00\u6B21\u3002",
|
|
1871
|
+
parameters: {
|
|
1872
|
+
type: "object",
|
|
1873
|
+
properties: {
|
|
1874
|
+
date: { type: "string", description: '\u6708-\u65E5\uFF0C\u4F8B\u5982 "10-26"' },
|
|
1875
|
+
name: { type: "string", description: "\u662F\u4EC0\u4E48\u65E5\u5B50" }
|
|
1876
|
+
},
|
|
1877
|
+
required: ["date", "name"]
|
|
1878
|
+
}
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
name: "ritual_list",
|
|
1882
|
+
tags: ["read"],
|
|
1883
|
+
description: "\u5217\u51FA\u5DF2\u8BB0\u7684\u7EAA\u5FF5\u65E5\u3002",
|
|
1884
|
+
parameters: { type: "object", properties: {} }
|
|
1804
1885
|
}
|
|
1805
1886
|
];
|
|
1806
1887
|
|
|
@@ -1822,6 +1903,10 @@ var HandsWorld = class {
|
|
|
1822
1903
|
pausedUntil = 0;
|
|
1823
1904
|
recent = [];
|
|
1824
1905
|
honchoClient = null;
|
|
1906
|
+
agendaTimer = null;
|
|
1907
|
+
agenda;
|
|
1908
|
+
affinity;
|
|
1909
|
+
ritual;
|
|
1825
1910
|
pollTimer = null;
|
|
1826
1911
|
dailyDiaryTimer = null;
|
|
1827
1912
|
lastDiaryDay = "";
|
|
@@ -1863,6 +1948,13 @@ var HandsWorld = class {
|
|
|
1863
1948
|
/* ---------- 记忆钩子 ---------- */
|
|
1864
1949
|
startHooks() {
|
|
1865
1950
|
if (this.pollTimer) return;
|
|
1951
|
+
const dir = this.opts.dataDir ?? ".";
|
|
1952
|
+
this.agenda = new JsonStore(dir, "agenda.json", []);
|
|
1953
|
+
this.affinity = new JsonStore(dir, "affinity.json", {});
|
|
1954
|
+
this.ritual = new JsonStore(dir, "ritual.json", { anniversaries: [] });
|
|
1955
|
+
this.agendaTimer = setInterval(() => {
|
|
1956
|
+
void this.checkAgenda();
|
|
1957
|
+
}, 3e4);
|
|
1866
1958
|
this.pollTimer = setInterval(() => {
|
|
1867
1959
|
void this.pollUserSpeech();
|
|
1868
1960
|
}, 5e3);
|
|
@@ -1888,6 +1980,63 @@ var HandsWorld = class {
|
|
|
1888
1980
|
this.pollTimer = null;
|
|
1889
1981
|
this.mineTimer = null;
|
|
1890
1982
|
}
|
|
1983
|
+
/** 每 30 秒看一次:日程到点投一条,早安/晚安/纪念日各一次。 */
|
|
1984
|
+
async checkAgenda() {
|
|
1985
|
+
const now = /* @__PURE__ */ new Date();
|
|
1986
|
+
const iso = now.toISOString();
|
|
1987
|
+
const items = this.agenda?.read() ?? [];
|
|
1988
|
+
let changed = false;
|
|
1989
|
+
for (const item of items) {
|
|
1990
|
+
if (item.done || item.fired || !item.at) continue;
|
|
1991
|
+
if (new Date(item.at).getTime() <= now.getTime()) {
|
|
1992
|
+
item.fired = true;
|
|
1993
|
+
changed = true;
|
|
1994
|
+
await this.pushEvent(`[\u65E5\u7A0B] \u5230\u70B9\u4E86\uFF1A${item.title}\uFF08${item.who} \u8981\u7684\uFF09`, "agenda.due", "agenda");
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
if (changed) this.agenda?.write(items);
|
|
1998
|
+
try {
|
|
1999
|
+
const st = this.ritualStore().read();
|
|
2000
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
2001
|
+
const today = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
|
|
2002
|
+
const hhmm = `${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
|
2003
|
+
const morning = this.opts.cfg.ritualMorning || "08:00";
|
|
2004
|
+
const night = this.opts.cfg.ritualNight || "23:00";
|
|
2005
|
+
let dirty = false;
|
|
2006
|
+
if (hhmm === morning && st.lastMorning !== today) {
|
|
2007
|
+
st.lastMorning = today;
|
|
2008
|
+
dirty = true;
|
|
2009
|
+
await this.pushEvent("[\u4EEA\u5F0F] \u65E9\u5B89\u65F6\u95F4\u5230\u4E86\uFF0C\u4E3B\u52A8\u8DDF\u4E3B\u4EBA\u8BF4\u53E5\u65E9\u5B89\u3002", "ritual.morning", "ritual");
|
|
2010
|
+
}
|
|
2011
|
+
if (hhmm === night && st.lastNight !== today) {
|
|
2012
|
+
st.lastNight = today;
|
|
2013
|
+
dirty = true;
|
|
2014
|
+
await this.pushEvent("[\u4EEA\u5F0F] \u665A\u5B89\u65F6\u95F4\u5230\u4E86\uFF0C\u8DDF\u4E3B\u4EBA\u9053\u4E2A\u665A\u5B89\u3002", "ritual.night", "ritual");
|
|
2015
|
+
}
|
|
2016
|
+
const md = `${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
|
|
2017
|
+
for (const a of st.anniversaries ?? []) {
|
|
2018
|
+
if (a.date === md && st.lastAnniversary !== today) {
|
|
2019
|
+
st.lastAnniversary = today;
|
|
2020
|
+
dirty = true;
|
|
2021
|
+
await this.pushEvent(`[\u4EEA\u5F0F] \u4ECA\u5929\u662F\u300C${a.name}\u300D\uFF0C\u8BB0\u5F97\u63D0\u4E00\u53E5\u3002`, "ritual.anniversary", "ritual");
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
if (dirty) this.ritualStore().write(st);
|
|
2025
|
+
} catch {
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
agendaStore() {
|
|
2029
|
+
if (!this.agenda) throw new Error("\u65E5\u7A0B\u8FD8\u6CA1\u51C6\u5907\u597D");
|
|
2030
|
+
return this.agenda;
|
|
2031
|
+
}
|
|
2032
|
+
affinityStore() {
|
|
2033
|
+
if (!this.affinity) throw new Error("\u5173\u7CFB\u518C\u8FD8\u6CA1\u51C6\u5907\u597D");
|
|
2034
|
+
return this.affinity;
|
|
2035
|
+
}
|
|
2036
|
+
ritualStore() {
|
|
2037
|
+
if (!this.ritual) throw new Error("\u4EEA\u5F0F\u518C\u8FD8\u6CA1\u51C6\u5907\u597D");
|
|
2038
|
+
return this.ritual;
|
|
2039
|
+
}
|
|
1891
2040
|
async pushEvent(text, type, senderKey) {
|
|
1892
2041
|
const host = this.host;
|
|
1893
2042
|
if (!host) return;
|
|
@@ -2118,6 +2267,70 @@ ${lines.join("\n")}
|
|
|
2118
2267
|
return await this.mediaClean(args);
|
|
2119
2268
|
case "screen_wake":
|
|
2120
2269
|
return await this.screenWake();
|
|
2270
|
+
case "agenda_add": {
|
|
2271
|
+
const title = typeof args.title === "string" ? args.title.trim() : "";
|
|
2272
|
+
if (!title) return failed("\u8981\u8BB0\u4EC0\u4E48\uFF1F");
|
|
2273
|
+
const at = normalizeWhen(typeof args.at === "string" ? args.at : "");
|
|
2274
|
+
const items = this.agendaStore().read();
|
|
2275
|
+
const id = "a" + Date.now().toString(36);
|
|
2276
|
+
items.push({ id, title, at, who: typeof args.who === "string" && args.who ? args.who : "\u4E3B\u4EBA", done: false });
|
|
2277
|
+
this.agendaStore().write(items);
|
|
2278
|
+
return at ? `\u8BB0\u4E0B\u4E86\uFF1A${title}\uFF0C${fmtWhen(at)} \u53EB\u4F60` : `\u8BB0\u4E0B\u4E86\uFF1A${title}\uFF08\u6CA1\u8BBE\u65F6\u95F4\uFF09`;
|
|
2279
|
+
}
|
|
2280
|
+
case "agenda_list": {
|
|
2281
|
+
const items = this.agendaStore().read().filter((i) => !i.done);
|
|
2282
|
+
if (items.length === 0) return "\u65E5\u7A0B\u662F\u7A7A\u7684\u3002";
|
|
2283
|
+
return items.map((i) => `- [${i.id}] ${i.title}${i.at ? " \xB7 " + fmtWhen(i.at) : ""}\uFF08${i.who}\uFF09`).join("\n");
|
|
2284
|
+
}
|
|
2285
|
+
case "agenda_done": {
|
|
2286
|
+
const id = typeof args.id === "string" ? args.id.trim() : "";
|
|
2287
|
+
const items = this.agendaStore().read();
|
|
2288
|
+
const hit = items.find((i) => i.id === id);
|
|
2289
|
+
if (!hit) return failed("\u6CA1\u6709\u8FD9\u6761\u65E5\u7A0B");
|
|
2290
|
+
hit.done = true;
|
|
2291
|
+
this.agendaStore().write(items);
|
|
2292
|
+
return `\u597D\u4E86\uFF1A\u300C${hit.title}\u300D\u5DF2\u5B8C\u6210`;
|
|
2293
|
+
}
|
|
2294
|
+
case "affinity_get": {
|
|
2295
|
+
const qq = typeof args.qq === "string" ? args.qq.trim() : "";
|
|
2296
|
+
if (!qq) return failed("\u8981\u67E5\u8C01\uFF1F");
|
|
2297
|
+
const book = this.affinityStore().read();
|
|
2298
|
+
const row = book[qq];
|
|
2299
|
+
if (!row) return `${qq} \u8FD8\u6CA1\u8BB0\u8FC7\uFF0C\u5206\u6570 0\uFF08\u4E00\u822C\uFF09\u3002`;
|
|
2300
|
+
return `${qq}\uFF1A${row.score} \u5206\uFF08${LEVELS(row.score)}\uFF09${row.slot ? "\uFF0C\u7B97\u300C" + row.slot + "\u300D" : ""}\u3002\u6700\u8FD1\uFF1A${(row.notes ?? []).slice(-3).map((n) => `${n.delta > 0 ? "+" : ""}${n.delta} ${n.why}`).join("\uFF1B") || "\u65E0"}`;
|
|
2301
|
+
}
|
|
2302
|
+
case "affinity_adjust": {
|
|
2303
|
+
const qq = typeof args.qq === "string" ? args.qq.trim() : "";
|
|
2304
|
+
const delta = Number(args.delta);
|
|
2305
|
+
if (!qq || !Number.isFinite(delta)) return failed("\u8981 qq \u548C delta");
|
|
2306
|
+
const why = typeof args.why === "string" ? args.why.trim() : "";
|
|
2307
|
+
const book = this.affinityStore().read();
|
|
2308
|
+
const row = book[qq] ?? { qq, score: 0, notes: [] };
|
|
2309
|
+
row.score = Math.max(-100, Math.min(100, row.score + delta));
|
|
2310
|
+
row.notes = [...row.notes ?? [], { at: (/* @__PURE__ */ new Date()).toISOString(), delta, why }].slice(-50);
|
|
2311
|
+
book[qq] = row;
|
|
2312
|
+
this.affinityStore().write(book);
|
|
2313
|
+
return `${qq} \u73B0\u5728\u662F ${row.score} \u5206\uFF08${LEVELS(row.score)}\uFF09`;
|
|
2314
|
+
}
|
|
2315
|
+
case "affinity_list": {
|
|
2316
|
+
const rows = Object.values(this.affinityStore().read()).sort((a, b) => b.score - a.score).slice(0, 8);
|
|
2317
|
+
if (rows.length === 0) return "\u5173\u7CFB\u518C\u8FD8\u662F\u7A7A\u7684\u3002";
|
|
2318
|
+
return rows.map((r) => `- ${r.qq}\uFF1A${r.score} \u5206\uFF08${LEVELS(r.score)}\uFF09${r.slot ? "\xB7 " + r.slot : ""}`).join("\n");
|
|
2319
|
+
}
|
|
2320
|
+
case "ritual_set": {
|
|
2321
|
+
const date = typeof args.date === "string" ? args.date.trim() : "";
|
|
2322
|
+
const name2 = typeof args.name === "string" ? args.name.trim() : "";
|
|
2323
|
+
if (!/^\d{1,2}-\d{1,2}$/.test(date) || !name2) return failed("date \u8981\u5199\u6210 \u6708-\u65E5\uFF0C\u6BD4\u5982 10-26");
|
|
2324
|
+
const st = this.ritualStore().read();
|
|
2325
|
+
st.anniversaries = [...(st.anniversaries ?? []).filter((a) => a.date !== date), { date, name: name2 }];
|
|
2326
|
+
this.ritualStore().write(st);
|
|
2327
|
+
return `\u8BB0\u4F4F\u4E86\uFF1A${date} \u662F\u300C${name2}\u300D`;
|
|
2328
|
+
}
|
|
2329
|
+
case "ritual_list": {
|
|
2330
|
+
const st = this.ritualStore().read();
|
|
2331
|
+
if (!st.anniversaries?.length) return "\u8FD8\u6CA1\u8BB0\u7EAA\u5FF5\u65E5\u3002";
|
|
2332
|
+
return st.anniversaries.map((a) => `- ${a.date} ${a.name}`).join("\n");
|
|
2333
|
+
}
|
|
2121
2334
|
case "qq_reply":
|
|
2122
2335
|
return await this.qqReply(args);
|
|
2123
2336
|
case "screen_unlock":
|
|
@@ -2665,6 +2878,33 @@ ${this.recent.map((r) => `- ${r}`).join("\n")}`);
|
|
|
2665
2878
|
function failed(text) {
|
|
2666
2879
|
return { text, failed: true };
|
|
2667
2880
|
}
|
|
2881
|
+
function normalizeWhen(input) {
|
|
2882
|
+
const text = input.trim();
|
|
2883
|
+
if (!text) return "";
|
|
2884
|
+
const full = /^(\d{4})-(\d{1,2})-(\d{1,2})[ T](\d{1,2}):(\d{2})$/.exec(text);
|
|
2885
|
+
if (full) {
|
|
2886
|
+
const d = new Date(Number(full[1]), Number(full[2]) - 1, Number(full[3]), Number(full[4]), Number(full[5]));
|
|
2887
|
+
return isNaN(d.getTime()) ? "" : d.toISOString();
|
|
2888
|
+
}
|
|
2889
|
+
const hm = /^(\d{1,2}):(\d{2})$/.exec(text);
|
|
2890
|
+
if (hm) {
|
|
2891
|
+
const now = /* @__PURE__ */ new Date();
|
|
2892
|
+
const d = new Date(now.getFullYear(), now.getMonth(), now.getDate(), Number(hm[1]), Number(hm[2]));
|
|
2893
|
+
if (d.getTime() <= now.getTime()) d.setDate(d.getDate() + 1);
|
|
2894
|
+
return d.toISOString();
|
|
2895
|
+
}
|
|
2896
|
+
const parsed = new Date(text);
|
|
2897
|
+
return isNaN(parsed.getTime()) ? "" : parsed.toISOString();
|
|
2898
|
+
}
|
|
2899
|
+
function fmtWhen(iso) {
|
|
2900
|
+
try {
|
|
2901
|
+
const d = new Date(iso);
|
|
2902
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
2903
|
+
return `${d.getMonth() + 1}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
2904
|
+
} catch {
|
|
2905
|
+
return iso;
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2668
2908
|
|
|
2669
2909
|
// src/definition.ts
|
|
2670
2910
|
function handsDefinition() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cortico-world-hands",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Cortico World: hands for the desktop pet — looks at the phone screen, then taps, swipes, pinches, drags, types and presses keys through whatever actuator the device actually has",
|
|
6
6
|
"license": "MIT",
|