cortico-world-hands 0.7.0 → 0.8.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 +146 -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,31 @@ 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
+ /** 画板:新开一张。 */
1067
+ async canvasNew(w = 512, h = 512, bg = "transparent") {
1068
+ const cfg = this.cfg();
1069
+ const credential = this.readToken();
1070
+ const t = credential ? `&t=${encodeURIComponent(credential)}` : "";
1071
+ const res = await get(this.port(cfg.handPort), `/canvas/new?w=${w}&h=${h}&bg=${encodeURIComponent(bg)}${t}`, ACTION_TIMEOUT_MS);
1072
+ return res.body.toString("utf8");
1073
+ }
1074
+ /** 画板:画一笔。 */
1075
+ async canvasStroke(points, color = "#111111", width = 4) {
1076
+ const cfg = this.cfg();
1077
+ const credential = this.readToken();
1078
+ const t = credential ? `t=${encodeURIComponent(credential)}` : "";
1079
+ const body = JSON.stringify({ points, color, width });
1080
+ const res = await post(this.port(cfg.handPort), `/canvas/stroke?${t}`, body, ACTION_TIMEOUT_MS);
1081
+ return res.body.toString("utf8");
1082
+ }
1083
+ /** 画板:撤销 / 清空 / 保存 / 列表。 */
1084
+ async canvasOp(op) {
1085
+ const cfg = this.cfg();
1086
+ const credential = this.readToken();
1087
+ const t = credential ? `t=${encodeURIComponent(credential)}` : "";
1088
+ 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);
1089
+ return res.body.toString("utf8");
1090
+ }
1034
1091
  /** 日记:写一篇。 */
1035
1092
  async diaryWrite(title, text, date) {
1036
1093
  const cfg = this.cfg();
@@ -1385,6 +1442,57 @@ var HANDS_TOOL_DECLS = [
1385
1442
  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
1443
  parameters: { type: "object", properties: {}, required: [] }
1387
1444
  },
1445
+ {
1446
+ name: "canvas_new",
1447
+ tags: ["act"],
1448
+ 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",
1449
+ parameters: {
1450
+ type: "object",
1451
+ properties: {
1452
+ w: { type: "integer", description: "\u5BBD\uFF0C\u9ED8\u8BA4 512" },
1453
+ h: { type: "integer", description: "\u9AD8\uFF0C\u9ED8\u8BA4 512" },
1454
+ bg: { type: "string", description: "transparent \u6216 white" }
1455
+ }
1456
+ }
1457
+ },
1458
+ {
1459
+ name: "canvas_stroke",
1460
+ tags: ["act"],
1461
+ 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",
1462
+ parameters: {
1463
+ type: "object",
1464
+ properties: {
1465
+ points: { type: "array", description: "\u5750\u6807 [[x,y],[x,y],\u2026]\uFF0C\u539F\u70B9\u662F\u753B\u5E03\u5DE6\u4E0A\u89D2" },
1466
+ color: { type: "string", description: "\u989C\u8272\uFF0C#RRGGBB" },
1467
+ width: { type: "integer", description: "\u7B14\u753B\u7C97\u7EC6\uFF0C\u9ED8\u8BA4 4" }
1468
+ },
1469
+ required: ["points"]
1470
+ }
1471
+ },
1472
+ {
1473
+ name: "canvas_undo",
1474
+ tags: ["act"],
1475
+ description: "\u64A4\u9500\u521A\u624D\u90A3\u4E00\u7B14\uFF08\u53EF\u4EE5\u8FDE\u7740\u64A4\u9500\uFF09\u3002",
1476
+ parameters: { type: "object", properties: {} }
1477
+ },
1478
+ {
1479
+ name: "canvas_clear",
1480
+ tags: ["act"],
1481
+ description: "\u6E05\u7A7A\u6574\u5F20\u753B\u5E03\uFF08\u53EA\u6E05\u7B14\u753B\uFF0C\u4E0D\u5220\u6587\u4EF6\uFF09\u3002",
1482
+ parameters: { type: "object", properties: {} }
1483
+ },
1484
+ {
1485
+ name: "canvas_save",
1486
+ tags: ["act"],
1487
+ 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",
1488
+ parameters: { type: "object", properties: {} }
1489
+ },
1490
+ {
1491
+ name: "canvas_list",
1492
+ tags: ["read"],
1493
+ description: "\u770B\u770B\u81EA\u5DF1\u753B\u8FC7\u54EA\u4E9B\u56FE\uFF08\u6587\u4EF6\u540D\u548C\u5730\u5740\uFF09\u3002",
1494
+ parameters: { type: "object", properties: {} }
1495
+ },
1388
1496
  {
1389
1497
  name: "skin_install",
1390
1498
  tags: ["act"],
@@ -1793,6 +1901,18 @@ ${lines.join("\n")}
1793
1901
  return await this.diaryRead(args);
1794
1902
  case "skin_install":
1795
1903
  return await this.skinInstall(args);
1904
+ case "canvas_new":
1905
+ return await this.canvasNew(args);
1906
+ case "canvas_stroke":
1907
+ return await this.canvasStroke(args);
1908
+ case "canvas_undo":
1909
+ return await this.canvasSimple("undo");
1910
+ case "canvas_clear":
1911
+ return await this.canvasSimple("clear");
1912
+ case "canvas_save":
1913
+ return await this.canvasSimple("save");
1914
+ case "canvas_list":
1915
+ return await this.canvasSimple("list");
1796
1916
  case "memory_audit":
1797
1917
  return await this.memoryAudit(args);
1798
1918
  case "memory_search":
@@ -1905,6 +2025,31 @@ ${lines.join("\n")}
1905
2025
  }
1906
2026
  return `\u8BB0\u7262\u4E86\uFF1A\u300C${key}\u300D\u2192 ${value}${cloud}`;
1907
2027
  }
2028
+ async canvasNew(args) {
2029
+ const w = args.w === void 0 ? 512 : Math.max(64, Math.min(2048, Math.round(Number(args.w))));
2030
+ const h = args.h === void 0 ? 512 : Math.max(64, Math.min(2048, Math.round(Number(args.h))));
2031
+ const bg = typeof args.bg === "string" && args.bg ? args.bg : "transparent";
2032
+ return await this.hands.canvasNew(w, h, bg);
2033
+ }
2034
+ async canvasStroke(args) {
2035
+ const raw = args.points;
2036
+ if (!Array.isArray(raw) || raw.length === 0) return failed("\u8981 points\uFF0C\u50CF [[10,10],[20,30]]\u3002");
2037
+ const points = [];
2038
+ for (const p of raw.slice(0, 200)) {
2039
+ if (Array.isArray(p) && p.length >= 2) {
2040
+ const x = Number(p[0]);
2041
+ const y = Number(p[1]);
2042
+ if (Number.isFinite(x) && Number.isFinite(y)) points.push([x, y]);
2043
+ }
2044
+ }
2045
+ if (points.length === 0) return failed("points \u91CC\u6CA1\u6709\u5408\u6CD5\u5750\u6807\u3002");
2046
+ const color = typeof args.color === "string" && /^#[0-9a-fA-F]{6}$/.test(args.color) ? args.color : "#111111";
2047
+ const width = args.width === void 0 ? 4 : Math.max(1, Math.min(40, Math.round(Number(args.width))));
2048
+ return await this.hands.canvasStroke(points, color, width);
2049
+ }
2050
+ async canvasSimple(op) {
2051
+ return await this.hands.canvasOp(op);
2052
+ }
1908
2053
  /** 装一件外部服装包:从本地 HTTP 拿包,写进桌宠 web 目录。 */
1909
2054
  async skinInstall(args) {
1910
2055
  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.8.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",