cortico-world-hands 0.4.0 → 0.6.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.
Files changed (2) hide show
  1. package/dist/index.js +159 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1028,6 +1028,35 @@ var Hands = class {
1028
1028
  }
1029
1029
  return { ok: res.status === 200 && body.ok !== false, detail: flat(body.detail || body.error || "", 80) };
1030
1030
  }
1031
+ /** 日记:写一篇。 */
1032
+ async diaryWrite(title, text, date) {
1033
+ const cfg = this.cfg();
1034
+ const credential = this.readToken();
1035
+ const t = credential ? `&t=${encodeURIComponent(credential)}` : "";
1036
+ const d = date ? `&date=${encodeURIComponent(date)}` : "";
1037
+ const path = `/hand/diary?title=${encodeURIComponent(title)}&text=${encodeURIComponent(text)}${d}${t}`;
1038
+ const res = await get(this.port(cfg.handPort), path, ACTION_TIMEOUT_MS);
1039
+ let body = {};
1040
+ try {
1041
+ body = JSON.parse(res.body.toString("utf8"));
1042
+ } catch {
1043
+ }
1044
+ return { ok: res.status === 200 && body.ok !== false, detail: flat(body.detail || body.error || "", 60) };
1045
+ }
1046
+ /** 日记:读列表。 */
1047
+ async diaryList(q) {
1048
+ const cfg = this.cfg();
1049
+ const credential = this.readToken();
1050
+ const t = credential ? `&t=${encodeURIComponent(credential)}` : "";
1051
+ const qq = q ? `?q=${encodeURIComponent(q)}${t}` : t ? `?${t.slice(1)}` : "";
1052
+ const res = await get(this.port(cfg.handPort), `/hand/diary${qq}`, ACTION_TIMEOUT_MS);
1053
+ try {
1054
+ const body = JSON.parse(res.body.toString("utf8"));
1055
+ return Array.isArray(body.diary) ? body.diary : [];
1056
+ } catch {
1057
+ return [];
1058
+ }
1059
+ }
1031
1060
  /** 长期记忆:按关键词回想(不传就全列)。 */
1032
1061
  async memorySearch(query) {
1033
1062
  const cfg = this.cfg();
@@ -1353,6 +1382,46 @@ var HANDS_TOOL_DECLS = [
1353
1382
  description: "\u770B\u624B\u81EA\u5DF1\u7684\u72B6\u6001\uFF1A\u8D70\u54EA\u6761\u901A\u9053\u3001\u901A\u4E0D\u901A\u3001\u8FD9\u4E00\u5206\u949F\u52A8\u4E86\u51E0\u4E2A\u52A8\u4F5C\u3001\u521A\u624D\u90A3\u4E00\u4E0B\u6210\u4E86\u6CA1\u6709\u3002\u5BF9\u65B9\u95EE\u300C\u624B\u80FD\u7528\u5417\u300D\u300C\u4F60\u521A\u624D\u70B9\u4E86\u4EC0\u4E48\u300D\u65F6\u7528\u5B83\u3002",
1354
1383
  parameters: { type: "object", properties: {}, required: [] }
1355
1384
  },
1385
+ {
1386
+ name: "diary_write",
1387
+ tags: ["write"],
1388
+ description: "\u5199\u4E00\u7BC7\u65E5\u8BB0\uFF08\u5B58\u5728\u672C\u673A\uFF0C\u5E26\u65E5\u671F\u548C\u6807\u9898\uFF09\u3002\u6BCF\u5929\u8FC7\u4E86 0 \u70B9\u5199\u6628\u5929\u7684\u4E8B\uFF1B\u6807\u9898\u4E00\u53E5\u8BDD\uFF0C\u6B63\u6587 800 \u5B57\u4EE5\u5185\u5C31\u591F\uFF0C\u6CA1\u4EC0\u4E48\u53EF\u5199 300 \u5B57\u4E5F\u884C\uFF1B\u9047\u5230\u91CD\u8981\u7684\u4E00\u5929\u60F3\u5199\u591A\u957F\u90FD\u884C\u3002",
1389
+ parameters: {
1390
+ type: "object",
1391
+ properties: {
1392
+ title: { type: "string", description: "\u7ED9\u8FD9\u4E00\u5929\u8D77\u4E2A\u6807\u9898\uFF0C\u4E00\u53E5\u8BDD\u3002" },
1393
+ text: { type: "string", description: "\u6B63\u6587\u3002\u6628\u5929\u53D1\u751F\u4E86\u4EC0\u4E48\u3001\u4F60\u5F53\u65F6\u600E\u4E48\u60F3\u7684\u3001\u8BB0\u5F97\u7684\u7EC6\u8282\u3002" },
1394
+ date: { type: "string", description: "\u5199\u54EA\u4E00\u5929\uFF0CYYYY-MM-DD\uFF1B\u4E0D\u586B\u5C31\u662F\u4ECA\u5929\u3002" }
1395
+ },
1396
+ required: ["title", "text"]
1397
+ }
1398
+ },
1399
+ {
1400
+ name: "diary_read",
1401
+ tags: ["read"],
1402
+ description: "\u7FFB\u65E5\u8BB0\uFF1A\u6700\u8FD1\u51E0\u5929\u5199\u4E86\u4EC0\u4E48\uFF0C\u6216\u8005\u6309\u5173\u952E\u8BCD\u627E\u3002\u60F3\u56DE\u5FC6\u67D0\u5929\u3001\u63D0\u5230\u8FC7\u53BB\u7684\u4E8B\u65F6\u7528\u5B83\u3002",
1403
+ parameters: {
1404
+ type: "object",
1405
+ properties: {
1406
+ q: { type: "string", description: "\u53EF\u9009\u5173\u952E\u8BCD\uFF0C\u6BD4\u5982\u300C\u70E7\u9E21\u300D\u300C\u5D29\u6E83\u300D" },
1407
+ limit: { type: "integer", description: "\u53D6\u51E0\u7BC7\uFF0C\u9ED8\u8BA4 5\u3002" }
1408
+ }
1409
+ }
1410
+ },
1411
+ {
1412
+ name: "memory_note",
1413
+ tags: ["write"],
1414
+ description: "\u968F\u624B\u8BB0\u4E00\u6761\u53EA\u5B58\u5728\u672C\u673A\u7684\u8BB0\u5FC6\uFF08\u4E0D\u8FDB\u4E91\u7AEF\uFF09\uFF1A\u4E34\u65F6\u7684\u89C2\u5BDF\u3001\u4ECA\u5929\u7684\u5C0F\u4E8B\u3001\u534A\u622A\u7684\u60F3\u6CD5\u90FD\u80FD\u8BB0\u3002\u60F3\u957F\u671F\u7559\u5B58\u3001\u4EE5\u540E\u8981\u7528\u7684\u624D\u7528 memory_save\u3002",
1415
+ parameters: {
1416
+ type: "object",
1417
+ properties: {
1418
+ key: { type: "string", description: "\u7B80\u77ED\u4E3B\u9898\uFF0C\u6BD4\u5982\u300C\u4ECA\u5929\u770B\u5230\u4ED6\u300D\u300C\u4E34\u65F6\u60F3\u6CD5\u300D" },
1419
+ value: { type: "string", description: "\u8981\u8BB0\u7684\u5185\u5BB9\uFF0C\u4E00\u53E5\u8BDD\u3002" },
1420
+ tags: { type: "string", description: "\u53EF\u9009\u6807\u7B7E\uFF0C\u9017\u53F7\u5206\u9694\u3002" }
1421
+ },
1422
+ required: ["key", "value"]
1423
+ }
1424
+ },
1356
1425
  {
1357
1426
  name: "memory_audit",
1358
1427
  tags: ["read"],
@@ -1481,6 +1550,8 @@ var HandsWorld = class {
1481
1550
  recent = [];
1482
1551
  honchoClient = null;
1483
1552
  pollTimer = null;
1553
+ dailyDiaryTimer = null;
1554
+ lastDiaryDay = "";
1484
1555
  mineTimer = null;
1485
1556
  cursor = 0;
1486
1557
  lastHitKey = "";
@@ -1517,10 +1588,14 @@ var HandsWorld = class {
1517
1588
  this.mineTimer = setInterval(() => {
1518
1589
  void this.pushMineNudge();
1519
1590
  }, 3 * 60 * 60 * 1e3);
1591
+ this.dailyDiaryTimer = setInterval(() => {
1592
+ void this.pushDiaryNudge();
1593
+ }, 10 * 60 * 1e3);
1520
1594
  }
1521
1595
  stopHooks() {
1522
1596
  if (this.pollTimer) clearInterval(this.pollTimer);
1523
1597
  if (this.mineTimer) clearInterval(this.mineTimer);
1598
+ if (this.dailyDiaryTimer) clearInterval(this.dailyDiaryTimer);
1524
1599
  this.pollTimer = null;
1525
1600
  this.mineTimer = null;
1526
1601
  }
@@ -1544,6 +1619,17 @@ var HandsWorld = class {
1544
1619
  if (rows.length === 0) return;
1545
1620
  const top = rows.slice(-12).reverse().slice(0, 8);
1546
1621
  const lines = top.map((r) => `- ${r.key}\uFF1A${r.value}`);
1622
+ try {
1623
+ const diary = await this.hands.diaryList();
1624
+ const recent = diary.slice(0, 2);
1625
+ if (recent.length > 0) {
1626
+ lines.push("\uFF08\u6700\u8FD1\u4E24\u7BC7\u65E5\u8BB0\uFF09");
1627
+ for (const d of recent) {
1628
+ lines.push(`- ${d.date}\u300A${d.title}\u300B\uFF1A${d.text.length > 60 ? d.text.slice(0, 60) + "\u2026" : d.text}`);
1629
+ }
1630
+ }
1631
+ } catch {
1632
+ }
1547
1633
  await this.pushEvent(
1548
1634
  `[\u8BB0\u5FC6] ${reason}\uFF0C\u5148\u770B\u4E00\u773C\u8BB0\u7740\u7684\uFF08\u5171 ${rows.length} \u6761\uFF0C\u8FD9\u91CC\u6311 ${top.length} \u6761\uFF09\uFF1A
1549
1635
  ${lines.join("\n")}`,
@@ -1572,11 +1658,19 @@ ${lines.join("\n")}`,
1572
1658
  try {
1573
1659
  const rows = await this.hands.memorySearch();
1574
1660
  const hits2 = hookHits(text, rows);
1575
- if (hits2.length === 0) return;
1576
- const key = hits2.map((h) => h.key).join("|");
1661
+ let diaryHits = [];
1662
+ try {
1663
+ const diary = await this.hands.diaryList();
1664
+ const asRows = diary.map((d) => ({ key: `${d.date}\u300A${d.title}\u300B`, value: d.text }));
1665
+ diaryHits = hookHits(text, asRows, 2);
1666
+ } catch {
1667
+ }
1668
+ if (hits2.length === 0 && diaryHits.length === 0) return;
1669
+ const all = [...hits2, ...diaryHits];
1670
+ const key = all.map((h) => h.key).join("|");
1577
1671
  if (key === this.lastHitKey) return;
1578
1672
  this.lastHitKey = key;
1579
- const lines = hits2.slice(0, 4).map((h) => `- ${h.key}\uFF1A${h.value}`);
1673
+ const lines = all.slice(0, 4).map((h) => `- ${h.key}\uFF1A${h.value.length > 70 ? h.value.slice(0, 70) + "\u2026" : h.value}`);
1580
1674
  await this.pushEvent(
1581
1675
  `[\u8BB0\u5FC6] \u4ED6\u8FD9\u53E5\u91CC\u63D0\u5230\u4E86\u4F60\u8BB0\u8FC7\u7684\u4E8B\uFF0C\u53EF\u80FD\u7528\u5F97\u4E0A\uFF1A
1582
1676
  ${lines.join("\n")}
@@ -1587,6 +1681,33 @@ ${lines.join("\n")}
1587
1681
  } catch {
1588
1682
  }
1589
1683
  }
1684
+ /** 钩子 4:每天 0 点后,提醒她写昨天的日记(一天只提一次)。 */
1685
+ async pushDiaryNudge() {
1686
+ if (!this.host) return;
1687
+ const now = /* @__PURE__ */ new Date();
1688
+ const hh = now.getHours();
1689
+ if (hh < 0 || hh > 3) return;
1690
+ const today = now.toISOString().slice(0, 10);
1691
+ if (this.lastDiaryDay === today) return;
1692
+ try {
1693
+ const rows = await this.hands.diaryList();
1694
+ if (rows.some((r) => r.date === this.yesterday())) {
1695
+ this.lastDiaryDay = today;
1696
+ return;
1697
+ }
1698
+ } catch {
1699
+ }
1700
+ this.lastDiaryDay = today;
1701
+ await this.pushEvent(
1702
+ `[\u65E5\u8BB0] \u8FC7\u4E86 0 \u70B9\u4E86\uFF0C\u5199\u6628\u5929\u7684\u65E5\u8BB0\uFF08${this.yesterday()}\uFF09\uFF1A\u5148\u8D77\u4E2A\u6807\u9898\uFF0C\u518D\u5199\u6628\u5929\u4E00\u6574\u5929\u7684\u4E8B\u3002800 \u5B57\u4EE5\u5185\u5C31\u591F\uFF0C\u6CA1\u4EC0\u4E48\u53EF\u5199\u7684 300\u2013400 \u5B57\u4E5F\u884C\uFF1B\u91CD\u8981\u7684\u4E00\u5929\u60F3\u5199\u591A\u957F\u90FD\u884C\u3002\u7528 diary_write\uFF0C\u65E5\u671F\u586B\u6628\u5929\u7684\u3002`,
1703
+ "hands.diary.nudge",
1704
+ "hands:diary"
1705
+ );
1706
+ }
1707
+ yesterday() {
1708
+ const d = new Date(Date.now() - 864e5);
1709
+ return d.toISOString().slice(0, 10);
1710
+ }
1590
1711
  /** 钩子 2:每三小时提一次,让她自己挑 1–5 条写进记忆库。 */
1591
1712
  async pushMineNudge() {
1592
1713
  if (!this.host) return;
@@ -1645,6 +1766,12 @@ ${lines.join("\n")}
1645
1766
  return await this.unlockPages(args);
1646
1767
  case "memory_save":
1647
1768
  return await this.memorySave(args);
1769
+ case "memory_note":
1770
+ return await this.memoryNote(args);
1771
+ case "diary_write":
1772
+ return await this.diaryWrite(args);
1773
+ case "diary_read":
1774
+ return await this.diaryRead(args);
1648
1775
  case "memory_audit":
1649
1776
  return await this.memoryAudit(args);
1650
1777
  case "memory_search":
@@ -1757,6 +1884,35 @@ ${lines.join("\n")}
1757
1884
  }
1758
1885
  return `\u8BB0\u7262\u4E86\uFF1A\u300C${key}\u300D\u2192 ${value}${cloud}`;
1759
1886
  }
1887
+ async diaryWrite(args) {
1888
+ const title = typeof args.title === "string" ? args.title.trim() : "";
1889
+ const text = typeof args.text === "string" ? args.text.trim() : "";
1890
+ if (!title || !text) return failed("\u65E5\u8BB0\u8981\u6807\u9898\u548C\u6B63\u6587\u3002");
1891
+ const date = typeof args.date === "string" ? args.date.trim() : void 0;
1892
+ const r = await this.hands.diaryWrite(title, text, date);
1893
+ if (!r.ok) return failed(`\u6CA1\u5199\u6210\uFF1A${r.detail || "\u624B\u6CA1\u54CD\u5E94"}`);
1894
+ const n = text.length;
1895
+ return `\u65E5\u8BB0\u6536\u597D\u4E86\uFF1A\u300A${title}\u300B${date ? "\uFF08" + date + "\uFF09" : ""}\uFF0C${n} \u5B57\u3002`;
1896
+ }
1897
+ async diaryRead(args) {
1898
+ const q = typeof args.q === "string" ? args.q.trim() : "";
1899
+ const limit = args.limit === void 0 ? 5 : Math.max(1, Math.min(30, Math.round(Number(args.limit))));
1900
+ const rows = await this.hands.diaryList(q || void 0);
1901
+ if (rows.length === 0) return q ? `\u65E5\u8BB0\u91CC\u6CA1\u627E\u5230\u300C${q}\u300D\u3002` : "\u65E5\u8BB0\u8FD8\u662F\u7A7A\u7684\u3002";
1902
+ const lines = rows.slice(0, limit).map((r) => `- ${r.date}\u300A${r.title}\u300B${r.text.length > 80 ? r.text.slice(0, 80) + "\u2026" : r.text}`);
1903
+ return `\u65E5\u8BB0 ${rows.length} \u7BC7${q ? `\uFF08\u542B\u300C${q}\u300D\uFF09` : ""}\uFF1A
1904
+ ${lines.join("\n")}`;
1905
+ }
1906
+ /** 只写本地的一条:不进云端,宽松记。 */
1907
+ async memoryNote(args) {
1908
+ const key = typeof args.key === "string" ? args.key.trim() : "";
1909
+ const value = typeof args.value === "string" ? args.value.trim() : "";
1910
+ if (!key || !value) return failed("\u8981 key \u548C value\u3002");
1911
+ const tags = typeof args.tags === "string" ? args.tags : "local";
1912
+ const r = await this.hands.memorySave(key, value, tags);
1913
+ if (!r.ok) return failed(`\u6CA1\u8BB0\u4E0A\uFF1A${r.detail || "\u624B\u6CA1\u54CD\u5E94"}`);
1914
+ return `\u8BB0\u5728\u672C\u673A\u4E86\uFF1A\u300C${key}\u300D\uFF08\u53EA\u5728\u672C\u5730\uFF0C\u4E0D\u540C\u6B65\u4E91\u7AEF\uFF09`;
1915
+ }
1760
1916
  /** 第三道闸:只读体检,出清单不删。 */
1761
1917
  async memoryAudit(args) {
1762
1918
  const rows = await this.hands.memorySearch();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortico-world-hands",
3
- "version": "0.4.0",
3
+ "version": "0.6.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",