cortico-world-hands 0.7.0 → 0.9.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 +200 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -496,7 +496,7 @@ var Honcho = class {
496
496
  // src/hands.ts
497
497
  import { execFile } from "node:child_process";
498
498
  import { readFileSync } from "node:fs";
499
- import { get as httpGet } from "node:http";
499
+ import { get as httpGet, request as httpRequest } from "node:http";
500
500
  var ACTION_TIMEOUT_MS = 6e3;
501
501
  var PROBE_TTL_MS = 2e4;
502
502
  var COORD_LIMIT = 2e4;
@@ -524,6 +524,38 @@ function get(port, path, timeoutMs) {
524
524
  req.on("error", (err) => reject(err));
525
525
  });
526
526
  }
527
+ async function post(port, path, body, timeoutMs) {
528
+ return new Promise((resolve, reject) => {
529
+ const data = Buffer.from(body, "utf8");
530
+ const req = httpRequest(
531
+ {
532
+ host: "127.0.0.1",
533
+ port,
534
+ path,
535
+ method: "POST",
536
+ timeout: timeoutMs,
537
+ headers: { "content-type": "application/json", "content-length": data.length }
538
+ },
539
+ (res) => {
540
+ const chunks = [];
541
+ res.on("data", (chunk) => chunks.push(chunk));
542
+ res.on("end", () => {
543
+ resolve({
544
+ status: res.statusCode ?? 0,
545
+ body: Buffer.concat(chunks),
546
+ header: (name) => {
547
+ const value = res.headers[name.toLowerCase()];
548
+ return Array.isArray(value) ? value[0] ?? "" : value ?? "";
549
+ }
550
+ });
551
+ });
552
+ }
553
+ );
554
+ req.on("timeout", () => req.destroy(new Error(`\u7B49\u592A\u4E45\uFF08${timeoutMs}ms\uFF09`)));
555
+ req.on("error", (err) => reject(err));
556
+ req.end(data);
557
+ });
558
+ }
527
559
  async function getJson(port, path, timeoutMs = 6e3) {
528
560
  try {
529
561
  const res = await get(port, path, timeoutMs);
@@ -1031,6 +1063,47 @@ var Hands = class {
1031
1063
  }
1032
1064
  return { ok: res.status === 200 && body.ok !== false, detail: flat(body.detail || body.error || "", 80) };
1033
1065
  }
1066
+ /** 唤醒屏幕(用 Shizuku 的 input keyevent 224)。 */
1067
+ async wakeScreen() {
1068
+ const cfg = this.cfg();
1069
+ const credential = this.readToken();
1070
+ const t = credential ? `t=${encodeURIComponent(credential)}` : "";
1071
+ const res = await post(this.port(cfg.handPort), `/hand/wake?${t}`, "", 15e3);
1072
+ return res.body.toString("utf8");
1073
+ }
1074
+ /** 息屏(可选,用来自己测唤醒)。 */
1075
+ async sleepScreen() {
1076
+ const cfg = this.cfg();
1077
+ const credential = this.readToken();
1078
+ const t = credential ? `t=${encodeURIComponent(credential)}` : "";
1079
+ const res = await post(this.port(cfg.handPort), `/hand/sleep?${t}`, "", 15e3);
1080
+ return res.body.toString("utf8");
1081
+ }
1082
+ /** 画板:新开一张。 */
1083
+ async canvasNew(w = 512, h = 512, bg = "transparent") {
1084
+ const cfg = this.cfg();
1085
+ const credential = this.readToken();
1086
+ const t = credential ? `&t=${encodeURIComponent(credential)}` : "";
1087
+ const res = await get(this.port(cfg.handPort), `/canvas/new?w=${w}&h=${h}&bg=${encodeURIComponent(bg)}${t}`, ACTION_TIMEOUT_MS);
1088
+ return res.body.toString("utf8");
1089
+ }
1090
+ /** 画板:画一笔。 */
1091
+ async canvasStroke(points, color = "#111111", width = 4) {
1092
+ const cfg = this.cfg();
1093
+ const credential = this.readToken();
1094
+ const t = credential ? `t=${encodeURIComponent(credential)}` : "";
1095
+ const body = JSON.stringify({ points, color, width });
1096
+ const res = await post(this.port(cfg.handPort), `/canvas/stroke?${t}`, body, ACTION_TIMEOUT_MS);
1097
+ return res.body.toString("utf8");
1098
+ }
1099
+ /** 画板:撤销 / 清空 / 保存 / 列表。 */
1100
+ async canvasOp(op) {
1101
+ const cfg = this.cfg();
1102
+ const credential = this.readToken();
1103
+ const t = credential ? `t=${encodeURIComponent(credential)}` : "";
1104
+ const res = op === "list" || op === "state" ? await get(this.port(cfg.handPort), `/canvas/${op}?${t}`, ACTION_TIMEOUT_MS) : await post(this.port(cfg.handPort), `/canvas/${op}?${t}`, "", ACTION_TIMEOUT_MS);
1105
+ return res.body.toString("utf8");
1106
+ }
1034
1107
  /** 日记:写一篇。 */
1035
1108
  async diaryWrite(title, text, date) {
1036
1109
  const cfg = this.cfg();
@@ -1385,6 +1458,69 @@ var HANDS_TOOL_DECLS = [
1385
1458
  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",
1386
1459
  parameters: { type: "object", properties: {}, required: [] }
1387
1460
  },
1461
+ {
1462
+ name: "screen_wake",
1463
+ tags: ["act"],
1464
+ description: "\u70B9\u4EAE\u5C4F\u5E55\uFF1A\u5C4F\u5E55\u9ED1\u7740\u4E5F\u80FD\u5524\u9192\uFF08\u7528 Shizuku \u7684\u7CFB\u7EDF\u6309\u952E\uFF0Croot/Shizuku \u4EFB\u4E00\u901A\u9053\uFF09\u3002\u4E3B\u4EBA\u8BF4\u300C\u4EAE\u4E00\u4E0B\u5C4F\u300D\u300C\u5E2E\u6211\u628A\u5C4F\u5E55\u70B9\u4EAE\u300D\u65F6\u7528\u5B83\uFF1B\u5931\u8D25\u4F1A\u8FD4\u56DE\u539F\u56E0\u3002",
1465
+ parameters: { type: "object", properties: {} }
1466
+ },
1467
+ {
1468
+ name: "screen_sleep",
1469
+ tags: ["act"],
1470
+ description: "\u628A\u5C4F\u5E55\u5173\u6389\uFF08\u606F\u5C4F\uFF09\u3002\u4E3B\u4EBA\u8BF4\u8981\u5173\u5C4F\u3001\u6216\u8005\u4F60\u60F3\u81EA\u5DF1\u6D4B\u4E00\u4E0B\u5524\u9192\u662F\u5426\u7BA1\u7528\u65F6\u7528\u5B83\u3002",
1471
+ parameters: { type: "object", properties: {} }
1472
+ },
1473
+ {
1474
+ name: "canvas_new",
1475
+ tags: ["act"],
1476
+ description: "\u65B0\u5F00\u4E00\u5F20\u753B\u5E03\uFF08\u9ED8\u8BA4 512\xD7512\uFF0C\u80CC\u666F\u900F\u660E\u6216\u767D\u8272\uFF09\uFF0C\u4F1A\u628A\u5F53\u524D\u8FD9\u5F20\u6E05\u6389\u3002",
1477
+ parameters: {
1478
+ type: "object",
1479
+ properties: {
1480
+ w: { type: "integer", description: "\u5BBD\uFF0C\u9ED8\u8BA4 512" },
1481
+ h: { type: "integer", description: "\u9AD8\uFF0C\u9ED8\u8BA4 512" },
1482
+ bg: { type: "string", description: "transparent \u6216 white" }
1483
+ }
1484
+ }
1485
+ },
1486
+ {
1487
+ name: "canvas_stroke",
1488
+ tags: ["act"],
1489
+ description: "\u5728\u753B\u5E03\u4E0A\u753B\u4E00\u7B14\uFF1A\u7ED9\u4E00\u4E32\u5750\u6807\u70B9\u3001\u989C\u8272\u3001\u7C97\u7EC6\u3002\u60F3\u753B\u66F2\u7EBF\u5C31\u591A\u7ED9\u70B9\uFF0C\u6BCF\u7B14\u6700\u591A\u51E0\u5341\u4E2A\u70B9\uFF1B\u753B\u6B6A\u4E86\u5C31 canvas_undo\u3002",
1490
+ parameters: {
1491
+ type: "object",
1492
+ properties: {
1493
+ points: { type: "array", description: "\u5750\u6807 [[x,y],[x,y],\u2026]\uFF0C\u539F\u70B9\u662F\u753B\u5E03\u5DE6\u4E0A\u89D2" },
1494
+ color: { type: "string", description: "\u989C\u8272\uFF0C#RRGGBB" },
1495
+ width: { type: "integer", description: "\u7B14\u753B\u7C97\u7EC6\uFF0C\u9ED8\u8BA4 4" }
1496
+ },
1497
+ required: ["points"]
1498
+ }
1499
+ },
1500
+ {
1501
+ name: "canvas_undo",
1502
+ tags: ["act"],
1503
+ description: "\u64A4\u9500\u521A\u624D\u90A3\u4E00\u7B14\uFF08\u53EF\u4EE5\u8FDE\u7740\u64A4\u9500\uFF09\u3002",
1504
+ parameters: { type: "object", properties: {} }
1505
+ },
1506
+ {
1507
+ name: "canvas_clear",
1508
+ tags: ["act"],
1509
+ description: "\u6E05\u7A7A\u6574\u5F20\u753B\u5E03\uFF08\u53EA\u6E05\u7B14\u753B\uFF0C\u4E0D\u5220\u6587\u4EF6\uFF09\u3002",
1510
+ parameters: { type: "object", properties: {} }
1511
+ },
1512
+ {
1513
+ name: "canvas_save",
1514
+ tags: ["act"],
1515
+ description: "\u628A\u753B\u5E03\u5B58\u6210 PNG\uFF0C\u843D\u5230 blobs/drawings/\u65E5\u671F-\u65F6\u95F4.png\uFF0C\u8FD4\u56DE\u8DEF\u5F84\u3002\u53EA\u65B0\u589E\u6587\u4EF6\uFF0C\u4E0D\u8986\u76D6\u65E7\u56FE\u3002",
1516
+ parameters: { type: "object", properties: {} }
1517
+ },
1518
+ {
1519
+ name: "canvas_list",
1520
+ tags: ["read"],
1521
+ description: "\u770B\u770B\u81EA\u5DF1\u753B\u8FC7\u54EA\u4E9B\u56FE\uFF08\u6587\u4EF6\u540D\u548C\u5730\u5740\uFF09\u3002",
1522
+ parameters: { type: "object", properties: {} }
1523
+ },
1388
1524
  {
1389
1525
  name: "skin_install",
1390
1526
  tags: ["act"],
@@ -1793,6 +1929,22 @@ ${lines.join("\n")}
1793
1929
  return await this.diaryRead(args);
1794
1930
  case "skin_install":
1795
1931
  return await this.skinInstall(args);
1932
+ case "screen_wake":
1933
+ return await this.screenWake();
1934
+ case "screen_sleep":
1935
+ return await this.screenSleep();
1936
+ case "canvas_new":
1937
+ return await this.canvasNew(args);
1938
+ case "canvas_stroke":
1939
+ return await this.canvasStroke(args);
1940
+ case "canvas_undo":
1941
+ return await this.canvasSimple("undo");
1942
+ case "canvas_clear":
1943
+ return await this.canvasSimple("clear");
1944
+ case "canvas_save":
1945
+ return await this.canvasSimple("save");
1946
+ case "canvas_list":
1947
+ return await this.canvasSimple("list");
1796
1948
  case "memory_audit":
1797
1949
  return await this.memoryAudit(args);
1798
1950
  case "memory_search":
@@ -1905,6 +2057,53 @@ ${lines.join("\n")}
1905
2057
  }
1906
2058
  return `\u8BB0\u7262\u4E86\uFF1A\u300C${key}\u300D\u2192 ${value}${cloud}`;
1907
2059
  }
2060
+ /** 点亮屏幕:成功说清楚,失败给原因。 */
2061
+ async screenWake() {
2062
+ const raw = await this.hands.wakeScreen();
2063
+ try {
2064
+ const r = JSON.parse(raw);
2065
+ if (r.ok) {
2066
+ return r.litBefore ? "\u5C4F\u5E55\u672C\u6765\u5C31\u662F\u4EAE\u7684\u3002" : "\u5C4F\u5E55\u70B9\u4EAE\u4E86\u3002";
2067
+ }
2068
+ return failed(r.error || "\u6CA1\u70B9\u4EAE\uFF0C\u539F\u56E0\u4E0D\u660E");
2069
+ } catch {
2070
+ return failed(raw.slice(0, 120));
2071
+ }
2072
+ }
2073
+ async screenSleep() {
2074
+ const raw = await this.hands.sleepScreen();
2075
+ try {
2076
+ const r = JSON.parse(raw);
2077
+ return r.ok ? "\u5C4F\u5E55\u5173\u6389\u4E86\u3002" : failed(r.error || "\u6CA1\u5173\u6389\uFF0C\u539F\u56E0\u4E0D\u660E");
2078
+ } catch {
2079
+ return failed(raw.slice(0, 120));
2080
+ }
2081
+ }
2082
+ async canvasNew(args) {
2083
+ const w = args.w === void 0 ? 512 : Math.max(64, Math.min(2048, Math.round(Number(args.w))));
2084
+ const h = args.h === void 0 ? 512 : Math.max(64, Math.min(2048, Math.round(Number(args.h))));
2085
+ const bg = typeof args.bg === "string" && args.bg ? args.bg : "transparent";
2086
+ return await this.hands.canvasNew(w, h, bg);
2087
+ }
2088
+ async canvasStroke(args) {
2089
+ const raw = args.points;
2090
+ if (!Array.isArray(raw) || raw.length === 0) return failed("\u8981 points\uFF0C\u50CF [[10,10],[20,30]]\u3002");
2091
+ const points = [];
2092
+ for (const p of raw.slice(0, 200)) {
2093
+ if (Array.isArray(p) && p.length >= 2) {
2094
+ const x = Number(p[0]);
2095
+ const y = Number(p[1]);
2096
+ if (Number.isFinite(x) && Number.isFinite(y)) points.push([x, y]);
2097
+ }
2098
+ }
2099
+ if (points.length === 0) return failed("points \u91CC\u6CA1\u6709\u5408\u6CD5\u5750\u6807\u3002");
2100
+ const color = typeof args.color === "string" && /^#[0-9a-fA-F]{6}$/.test(args.color) ? args.color : "#111111";
2101
+ const width = args.width === void 0 ? 4 : Math.max(1, Math.min(40, Math.round(Number(args.width))));
2102
+ return await this.hands.canvasStroke(points, color, width);
2103
+ }
2104
+ async canvasSimple(op) {
2105
+ return await this.hands.canvasOp(op);
2106
+ }
1908
2107
  /** 装一件外部服装包:从本地 HTTP 拿包,写进桌宠 web 目录。 */
1909
2108
  async skinInstall(args) {
1910
2109
  const url = typeof args.url === "string" && args.url.trim() ? args.url.trim() : this.opts.cfg.skinPackUrl || "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortico-world-hands",
3
- "version": "0.7.0",
3
+ "version": "0.9.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",