cortico-world-hands 0.1.5 → 0.1.7

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 +129 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -670,6 +670,43 @@ var Hands = class {
670
670
  const ms = milliseconds(opts.ms, 900);
671
671
  return this.perform({ kind: "drag", x1: a, y1: b, x2: c, y2: d, ms });
672
672
  }
673
+ /** 长期记忆:存/改一条事实。 */
674
+ async memorySave(key, value, tags) {
675
+ const cfg = this.cfg();
676
+ const credential = this.readToken();
677
+ const t = credential ? `&t=${encodeURIComponent(credential)}` : "";
678
+ const tg = tags ? `&tags=${encodeURIComponent(tags)}` : "";
679
+ const path = `/hand/memory?key=${encodeURIComponent(key)}&value=${encodeURIComponent(value)}${tg}${t}`;
680
+ const res = await get(this.port(cfg.handPort), path, ACTION_TIMEOUT_MS);
681
+ let body = {};
682
+ try {
683
+ body = JSON.parse(res.body.toString("utf8"));
684
+ } catch {
685
+ }
686
+ return { ok: res.status === 200 && body.ok !== false, detail: flat(body.detail || body.error || "", 80) };
687
+ }
688
+ /** 长期记忆:按关键词回想(不传就全列)。 */
689
+ async memorySearch(query) {
690
+ const cfg = this.cfg();
691
+ const credential = this.readToken();
692
+ const t = credential ? `&t=${encodeURIComponent(credential)}` : "";
693
+ const q = query ? `?q=${encodeURIComponent(query)}${t}` : t ? `?${t.slice(1)}` : "";
694
+ const res = await get(this.port(cfg.handPort), `/hand/memories${q}`, ACTION_TIMEOUT_MS);
695
+ try {
696
+ const body = JSON.parse(res.body.toString("utf8"));
697
+ return Array.isArray(body.memories) ? body.memories : [];
698
+ } catch {
699
+ return [];
700
+ }
701
+ }
702
+ /** 长期记忆:忘掉一条。 */
703
+ async memoryForget(key) {
704
+ const cfg = this.cfg();
705
+ const credential = this.readToken();
706
+ const t = credential ? `&t=${encodeURIComponent(credential)}` : "";
707
+ const res = await get(this.port(cfg.handPort), `/hand/memory/forget?key=${encodeURIComponent(key)}${t}`, ACTION_TIMEOUT_MS);
708
+ return res.status === 200;
709
+ }
673
710
  /** 留言板:写一条。 */
674
711
  async noteAdd(text, kind) {
675
712
  const cfg = this.cfg();
@@ -698,6 +735,15 @@ var Hands = class {
698
735
  return [];
699
736
  }
700
737
  }
738
+ /** 留言板:未完成的待办条数(状态灯里显示)。 */
739
+ async notePending() {
740
+ try {
741
+ const notes = await this.noteList();
742
+ return notes.filter((n) => !n.done).length;
743
+ } catch {
744
+ return 0;
745
+ }
746
+ }
701
747
  /** 留言板:划掉一条。 */
702
748
  async noteDone(id) {
703
749
  const cfg = this.cfg();
@@ -741,6 +787,7 @@ var Hands = class {
741
787
  if (!state.ok) throw new HandError(`\u624B\u73B0\u5728\u52A8\u4E0D\u4E86\uFF1A${state.detail}`);
742
788
  const where = await this.screenGuard();
743
789
  await this.throttle();
790
+ this.lookCache = null;
744
791
  const described = describeCommand(command);
745
792
  const cfg = this.cfg();
746
793
  if (cfg.dryRun) {
@@ -764,7 +811,18 @@ var Hands = class {
764
811
  }
765
812
  }
766
813
  /** 看一眼屏幕。detail: both(画面加文字,默认)、screen(只要画面)、text(只要文字)。 */
814
+ lookCache = null;
767
815
  async look(detail = "both") {
816
+ const now = Date.now();
817
+ if (this.lookCache && this.lookCache.detail === detail && now - this.lookCache.at < 1200) {
818
+ this.looks += 1;
819
+ return this.lookCache.report;
820
+ }
821
+ const report = await this.lookFresh(detail);
822
+ this.lookCache = { at: Date.now(), detail, report };
823
+ return report;
824
+ }
825
+ async lookFresh(detail = "both") {
768
826
  const cfg = this.cfg();
769
827
  const health = await this.eyes.health();
770
828
  if (!health?.ok) {
@@ -952,6 +1010,42 @@ var HANDS_TOOL_DECLS = [
952
1010
  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",
953
1011
  parameters: { type: "object", properties: {}, required: [] }
954
1012
  },
1013
+ {
1014
+ name: "memory_save",
1015
+ tags: ["act"],
1016
+ description: "\u5F80\u957F\u671F\u8BB0\u5FC6\u91CC\u5B58\u4E00\u6761\u4E8B\u5B9E\uFF1A\u4E3B\u4EBA\u7684\u540D\u5B57/\u79F0\u547C\u3001\u559C\u597D\u5FCC\u8BB3\u3001\u4F5C\u606F\u4E60\u60EF\u3001\u6B63\u5728\u505A\u7684\u4E8B\u3001\u7EA6\u5B9A\u3001\u91CD\u8981\u65E5\u5B50\u3001\u4F60\u7B54\u5E94\u8FC7\u7684\u4E8B\u3002key \u7528\u7B80\u77ED\u4E3B\u9898\uFF08\u5982\u300C\u4E3B\u4EBA\u79F0\u547C\u300D\u300C\u5496\u5561\u504F\u597D\u300D\u300C\u5468\u672B\u5B89\u6392\u300D\uFF09\uFF0Cvalue \u5199\u6E05\u695A\uFF1B\u540C\u4E00\u4E2A key \u4F1A\u8986\u76D6\u3002",
1017
+ parameters: {
1018
+ type: "object",
1019
+ properties: {
1020
+ key: { type: "string", description: "\u7B80\u77ED\u4E3B\u9898\uFF0C\u6BD4\u5982\u300C\u4E3B\u4EBA\u7684\u732B\u300D\u300C\u751F\u65E5\u300D\u300C\u4E0D\u559C\u6B22\u300D" },
1021
+ value: { type: "string", description: "\u8BB0\u7684\u5177\u4F53\u5185\u5BB9\uFF0C\u4E00\u53E5\u8BDD\u8BF4\u6E05\u3002" },
1022
+ tags: { type: "string", description: "\u53EF\u9009\u6807\u7B7E\uFF0C\u9017\u53F7\u5206\u9694\u3002" }
1023
+ },
1024
+ required: ["key", "value"]
1025
+ }
1026
+ },
1027
+ {
1028
+ name: "memory_search",
1029
+ tags: ["read"],
1030
+ description: "\u56DE\u60F3\u957F\u671F\u8BB0\u5FC6\uFF1A\u6309\u5173\u952E\u8BCD\u67E5\uFF08\u4E0D\u4F20\u5173\u952E\u8BCD\u5C31\u5168\u90E8\u5217\u51FA\uFF09\u3002\u804A\u5929\u91CC\u6D89\u53CA\u4E3B\u4EBA\u7684\u504F\u597D\u3001\u7EA6\u5B9A\u3001\u4EE5\u524D\u8BF4\u8FC7\u7684\u4E8B\u65F6\u5148\u67E5\u4E00\u4E0B\uFF0C\u522B\u51ED\u611F\u89C9\u3002",
1031
+ parameters: {
1032
+ type: "object",
1033
+ properties: {
1034
+ query: { type: "string", description: "\u5173\u952E\u8BCD\uFF0C\u6BD4\u5982\u300C\u5496\u5561\u300D\u300C\u751F\u65E5\u300D\uFF1B\u7559\u7A7A\u770B\u5168\u90E8\u3002" }
1035
+ },
1036
+ required: []
1037
+ }
1038
+ },
1039
+ {
1040
+ name: "memory_forget",
1041
+ tags: ["act"],
1042
+ description: "\u5FD8\u6389\u4E00\u6761\u957F\u671F\u8BB0\u5FC6\uFF08\u8BB0\u9519\u4E86\u3001\u8FC7\u65F6\u4E86\u3001\u4E3B\u4EBA\u8BF4\u522B\u8BB0\u4E86\uFF09\u3002",
1043
+ parameters: {
1044
+ type: "object",
1045
+ properties: { key: { type: "string", description: "\u8981\u5FD8\u6389\u7684\u4E3B\u9898 key\u3002" } },
1046
+ required: ["key"]
1047
+ }
1048
+ },
955
1049
  {
956
1050
  name: "note_add",
957
1051
  tags: ["act"],
@@ -1078,7 +1172,13 @@ var HandsWorld = class {
1078
1172
  case "hand_key":
1079
1173
  return await this.key(args);
1080
1174
  case "hand_status":
1081
- return this.statusText();
1175
+ return await this.statusText();
1176
+ case "memory_save":
1177
+ return await this.memorySave(args);
1178
+ case "memory_search":
1179
+ return await this.memorySearch(args);
1180
+ case "memory_forget":
1181
+ return await this.memoryForget(args);
1082
1182
  case "note_add":
1083
1183
  return await this.noteAdd(args);
1084
1184
  case "note_list":
@@ -1115,6 +1215,28 @@ var HandsWorld = class {
1115
1215
  return { text: report.text, ...blobs.length ? { blobs } : {} };
1116
1216
  }
1117
1217
  /** 给文字就先在屏幕上找,找到唯一一处才点;给坐标就直接点。 */
1218
+ async memorySave(args) {
1219
+ const key = typeof args.key === "string" ? args.key.trim() : "";
1220
+ const value = typeof args.value === "string" ? args.value.trim() : "";
1221
+ if (!key || !value) return failed("\u8981 key \u548C value\u3002");
1222
+ const tags = typeof args.tags === "string" ? args.tags : void 0;
1223
+ const r = await this.hands.memorySave(key, value, tags);
1224
+ return r.ok ? `\u8BB0\u7262\u4E86\uFF1A\u300C${key}\u300D\u2192 ${value}` : failed(`\u6CA1\u8BB0\u4F4F\uFF1A${r.detail || "\u624B\u6CA1\u54CD\u5E94"}`);
1225
+ }
1226
+ async memorySearch(args) {
1227
+ const query = typeof args.query === "string" ? args.query.trim() : "";
1228
+ const rows = await this.hands.memorySearch(query);
1229
+ if (rows.length === 0) return query ? `\u8BB0\u5FC6\u91CC\u6CA1\u6709\u548C\u300C${query}\u300D\u76F8\u5173\u7684\u3002` : "\u957F\u671F\u8BB0\u5FC6\u8FD8\u662F\u7A7A\u7684\u3002";
1230
+ const lines = rows.slice(0, 30).map((r) => `- ${r.key}\uFF1A${r.value}${r.ts ? `\uFF08${r.ts}\uFF09` : ""}`).join("\n");
1231
+ return `\u60F3\u8D77 ${rows.length} \u6761\uFF1A
1232
+ ${lines}`;
1233
+ }
1234
+ async memoryForget(args) {
1235
+ const key = typeof args.key === "string" ? args.key.trim() : "";
1236
+ if (!key) return failed("\u8981\u5FD8\u6389\u54EA\u4E2A key\uFF1F");
1237
+ const ok = await this.hands.memoryForget(key);
1238
+ return ok ? `\u5FD8\u4E86\u300C${key}\u300D\u3002` : failed(`\u6CA1\u627E\u5230\u300C${key}\u300D\u8FD9\u6761\u8BB0\u5FC6\u3002`);
1239
+ }
1118
1240
  async noteAdd(args) {
1119
1241
  const text = typeof args.text === "string" ? args.text.trim() : "";
1120
1242
  if (!text) return failed("\u8981\u5199\u4EC0\u4E48\uFF1F\u7ED9 text\u3002");
@@ -1230,7 +1352,7 @@ ${list}`);
1230
1352
  this.note(receipt);
1231
1353
  return receipt.text;
1232
1354
  }
1233
- statusText() {
1355
+ async statusText() {
1234
1356
  const cfg = this.opts.cfg;
1235
1357
  const state = this.hands.state();
1236
1358
  const stats = this.hands.stats();
@@ -1241,6 +1363,11 @@ ${list}`);
1241
1363
  `\u8FD9\u4E00\u5206\u949F\uFF1A${stats.inWindow}\uFF0F${Math.max(1, Math.round(cfg.maxActionsPerMinute) || 30)} \u4E0B\uFF1B\u7D2F\u8BA1\u52A8\u8FC7 ${stats.acts} \u6B21\u3001\u770B\u8FC7 ${stats.looks} \u6B21`
1242
1364
  ];
1243
1365
  if (this.pausedUntil > Date.now()) lines.push(`\u53EB\u505C\u4E2D\uFF1A\u8FD8\u6709 ${Math.ceil((this.pausedUntil - Date.now()) / 1e3)} \u79D2`);
1366
+ try {
1367
+ const pending = await this.hands.notePending();
1368
+ if (pending > 0) lines.push(`\u7559\u8A00\u677F\uFF1A\u8FD8\u6709 ${pending} \u6761\u6CA1\u5212\u6389`);
1369
+ } catch {
1370
+ }
1244
1371
  if (this.recent.length) lines.push(`\u6700\u8FD1\uFF1A
1245
1372
  ${this.recent.map((r) => `- ${r}`).join("\n")}`);
1246
1373
  return lines.join("\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortico-world-hands",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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",