@agent-wechat/cli 0.15.0 → 0.15.2

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 (3) hide show
  1. package/README.md +6 -0
  2. package/dist/cli.js +32 -9
  3. package/package.json +4 -3
package/README.md CHANGED
@@ -90,6 +90,12 @@ Send options:
90
90
 
91
91
  Media options:
92
92
  - `--output <path>` — save to a specific file path
93
+ - `--full` — require an original-resolution image
94
+ - `--thumbnail` — save the cached preview
95
+ - `--best` — explicitly choose the default best-available image behavior
96
+
97
+ Media retrieval does not open a chat. Use `wx chats open <chatId>` separately
98
+ if WeChat needs to cache a regular photo's standard-size copy.
93
99
 
94
100
  ### Sessions
95
101
 
package/dist/cli.js CHANGED
@@ -7870,11 +7870,15 @@ var getMediaParamsSchema = external_exports.object({
7870
7870
  quality: external_exports.enum(["full", "thumbnail"]).optional()
7871
7871
  });
7872
7872
  var mediaResultSchema = external_exports.object({
7873
- type: external_exports.enum(["image", "emoji", "voice", "video", "file", "pending", "unsupported"]),
7873
+ type: external_exports.enum(["image", "emoji", "voice", "video", "file", "pending", "expired", "unsupported"]),
7874
7874
  data: external_exports.string().optional(),
7875
7875
  url: external_exports.string().optional(),
7876
7876
  format: external_exports.string(),
7877
- filename: external_exports.string()
7877
+ filename: external_exports.string(),
7878
+ quality: external_exports.enum(["full", "standard", "thumbnail"]).optional(),
7879
+ reason: external_exports.string().optional(),
7880
+ expiresAt: external_exports.number().int().positive().optional(),
7881
+ retryable: external_exports.boolean().optional()
7878
7882
  });
7879
7883
  var agentConfigSchema = external_exports.object({
7880
7884
  maxTurns: external_exports.number().int().positive().default(30),
@@ -7921,6 +7925,14 @@ function createSubscriptionClient(options) {
7921
7925
  };
7922
7926
  }
7923
7927
 
7928
+ // src/lib/media-status.ts
7929
+ function expiredMediaMessage(result) {
7930
+ if (result.type !== "expired" || result.data) return void 0;
7931
+ const expiry = typeof result.expiresAt === "number" ? new Date(result.expiresAt * 1e3) : void 0;
7932
+ const when = expiry && Number.isFinite(expiry.getTime()) ? ` (${expiry.toISOString()})` : "";
7933
+ return `Media has expired${when} and no cached copy is available. Ask the sender to resend; automatic retries will not recover it.`;
7934
+ }
7935
+
7924
7936
  // src/cli.ts
7925
7937
  import { spawn, execSync } from "child_process";
7926
7938
  import { randomBytes } from "crypto";
@@ -7929,7 +7941,7 @@ import qrTerminal from "qrcode-terminal";
7929
7941
  import os from "os";
7930
7942
  import path from "path";
7931
7943
  import { fileURLToPath } from "url";
7932
- var VERSION = "0.15.0";
7944
+ var VERSION = "0.15.2";
7933
7945
  var CONTAINER_NAME = "agent-wechat";
7934
7946
  var GHCR_IMAGE = "ghcr.io/thisnick/agent-wechat";
7935
7947
  var DEFAULT_PORT = 6174;
@@ -8075,8 +8087,13 @@ var messagesCmd = program2.command("messages").description("Message commands");
8075
8087
  messagesCmd.command("list <chatId>").description("List messages for a chat").option("-l, --limit <number>", "Maximum number of messages", "50").option("-o, --offset <number>", "Skip first N messages", "0").option("-j, --json", "Output as JSON").action(async (chatId, opts) => {
8076
8088
  await cmdMessages(getClient(), chatId, parseInt(opts.limit, 10), parseInt(opts.offset, 10), opts.json ?? false);
8077
8089
  });
8078
- messagesCmd.command("media <chatId> <localId>").description("Save a media attachment (full-resolution image, file, or voice)").option("--thumbnail", "Retrieve an image thumbnail instead of full resolution").option("-o, --output <path>", "Output file path").action(async (chatId, localIdStr, opts) => {
8079
- await cmdMedia(getClient(), chatId, parseInt(localIdStr, 10), opts.output, opts.thumbnail);
8090
+ messagesCmd.command("media <chatId> <localId>").description("Save a media attachment (best available image, file, or voice)").option("--full", "Require the original-resolution image").option("--thumbnail", "Retrieve an image thumbnail instead of full resolution").option("--best", "Retrieve the best available image (default)").option("-o, --output <path>", "Output file path").action(async (chatId, localIdStr, opts) => {
8091
+ if (Number(!!opts.full) + Number(!!opts.thumbnail) + Number(!!opts.best) > 1) {
8092
+ console.error("Choose only one of --full, --thumbnail, or --best.");
8093
+ process.exit(1);
8094
+ }
8095
+ const quality = opts.full ? "full" : opts.thumbnail ? "thumbnail" : "best";
8096
+ await cmdMedia(getClient(), chatId, parseInt(localIdStr, 10), opts.output, quality);
8080
8097
  });
8081
8098
  messagesCmd.command("send <chatId>").description("Send a message to a chat").option("--text <text>", "Text message to send").option("--image <path>", "Image file to send").option("--file <path>", "File to send").option("--voice <path>", "Record audio as one or more voice notes").option("--detach", "Return after the voice job is queued").action(async (chatId, opts) => {
8082
8099
  if (!opts.text && !opts.image && !opts.file && !opts.voice) {
@@ -8390,8 +8407,13 @@ async function cmdMessages(client, chatId, limit = 50, offset = 0, json = false)
8390
8407
  console.log(`
8391
8408
  ${messages.length} message(s) shown.`);
8392
8409
  }
8393
- async function cmdMedia(client, chatId, localId, outputPath, thumbnail = false) {
8394
- const result = await client.getMedia(chatId, localId, thumbnail ? "thumbnail" : "full");
8410
+ async function cmdMedia(client, chatId, localId, outputPath, quality = "best") {
8411
+ const result = await client.getMedia(chatId, localId, quality);
8412
+ const expired = expiredMediaMessage(result);
8413
+ if (expired) {
8414
+ console.error(expired);
8415
+ process.exit(1);
8416
+ }
8395
8417
  if (result.type === "unsupported") {
8396
8418
  console.error("No media found for this message (unsupported type or not found).");
8397
8419
  process.exit(1);
@@ -8404,9 +8426,10 @@ async function cmdMedia(client, chatId, localId, outputPath, thumbnail = false)
8404
8426
  if (result.data) {
8405
8427
  const buffer = Buffer.from(result.data, "base64");
8406
8428
  fs.writeFileSync(outFile, buffer);
8407
- console.log(`Saved ${result.type} to ${outFile} (${buffer.length} bytes)`);
8429
+ const variant = result.type === "image" && result.quality ? ` (${result.quality})` : "";
8430
+ console.log(`Saved ${result.type}${variant} to ${outFile} (${buffer.length} bytes)`);
8408
8431
  } else if (result.type === "image") {
8409
- console.error(`Requested image ${thumbnail ? "thumbnail" : "full resolution"} is not yet available.`);
8432
+ console.error(`Requested image ${quality} is not yet available.${quality === "full" ? " Regular phone sends may have no Original copy; try without --full." : ""}`);
8410
8433
  process.exit(1);
8411
8434
  } else if (result.type === "video") {
8412
8435
  console.error("Video not yet downloaded by WeChat. Try playing the video in the app first.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-wechat/cli",
3
- "version": "0.15.0",
3
+ "version": "0.15.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "wx": "./dist/cli.js"
@@ -17,7 +17,7 @@
17
17
  "@types/node": "^22",
18
18
  "@types/qrcode-terminal": "^0.12.2",
19
19
  "typescript": "^5.4.5",
20
- "@agent-wechat/shared": "0.3.0"
20
+ "@agent-wechat/shared": "0.3.1"
21
21
  },
22
22
  "publishConfig": {
23
23
  "access": "public",
@@ -30,6 +30,7 @@
30
30
  },
31
31
  "scripts": {
32
32
  "build": "node build.js",
33
- "typecheck": "tsc --noEmit"
33
+ "typecheck": "tsc --noEmit",
34
+ "test": "node --test --experimental-strip-types src/lib/*.test.mjs"
34
35
  }
35
36
  }