openzca 0.1.21 → 0.1.22

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/cli.js +105 -3
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -703,6 +703,98 @@ function output(value, asJson = false) {
703
703
  function asThreadType(groupFlag) {
704
704
  return groupFlag ? ThreadType.Group : ThreadType.User;
705
705
  }
706
+ function parseBooleanFromEnv(name, fallback) {
707
+ const raw = process.env[name]?.trim();
708
+ if (!raw) return fallback;
709
+ const normalized = raw.toLowerCase();
710
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
711
+ return true;
712
+ }
713
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
714
+ return false;
715
+ }
716
+ return fallback;
717
+ }
718
+ function normalizeCachedId(value) {
719
+ if (typeof value === "string") {
720
+ const trimmed = value.trim();
721
+ return trimmed.length > 0 ? trimmed : null;
722
+ }
723
+ if (typeof value === "number" && Number.isFinite(value)) {
724
+ return String(Math.trunc(value));
725
+ }
726
+ return null;
727
+ }
728
+ function collectIdsFromCacheEntries(entries, keys) {
729
+ const ids = /* @__PURE__ */ new Set();
730
+ for (const entry of entries) {
731
+ if (!entry || typeof entry !== "object") continue;
732
+ const row = entry;
733
+ for (const key of keys) {
734
+ const normalized = normalizeCachedId(row[key]);
735
+ if (normalized) {
736
+ ids.add(normalized);
737
+ }
738
+ }
739
+ }
740
+ return ids;
741
+ }
742
+ async function resolveUploadThreadType(api, profile, threadId, groupFlag, command) {
743
+ if (groupFlag) {
744
+ return { type: ThreadType.Group, reason: "explicit_group_flag" };
745
+ }
746
+ const autoDetectEnabled = parseBooleanFromEnv("OPENZCA_UPLOAD_AUTO_THREAD_TYPE", true);
747
+ if (!autoDetectEnabled) {
748
+ return { type: ThreadType.User, reason: "auto_detect_disabled" };
749
+ }
750
+ try {
751
+ const cache = await readCache(profile);
752
+ const groupIds = collectIdsFromCacheEntries(cache.groups, ["groupId", "grid", "threadId", "id"]);
753
+ if (groupIds.has(threadId)) {
754
+ return { type: ThreadType.Group, reason: "cache_group_match" };
755
+ }
756
+ const friendIds = collectIdsFromCacheEntries(cache.friends, ["userId", "uid", "id", "threadId"]);
757
+ if (friendIds.has(threadId)) {
758
+ return { type: ThreadType.User, reason: "cache_friend_match" };
759
+ }
760
+ } catch (error) {
761
+ writeDebugLine(
762
+ "msg.upload.thread_type.cache_error",
763
+ {
764
+ profile,
765
+ threadId,
766
+ message: toErrorText(error)
767
+ },
768
+ command
769
+ );
770
+ }
771
+ const probeEnabled = parseBooleanFromEnv("OPENZCA_UPLOAD_GROUP_PROBE", true);
772
+ if (!probeEnabled) {
773
+ return { type: ThreadType.User, reason: "probe_disabled" };
774
+ }
775
+ const probeTimeoutMs = parsePositiveIntFromEnv("OPENZCA_UPLOAD_GROUP_PROBE_TIMEOUT_MS", 5e3);
776
+ try {
777
+ const groupInfo = await withTimeout(
778
+ api.getGroupInfo(threadId),
779
+ probeTimeoutMs,
780
+ `Timed out waiting ${probeTimeoutMs}ms while probing group thread type.`
781
+ );
782
+ if (groupInfo?.gridInfoMap?.[threadId]) {
783
+ return { type: ThreadType.Group, reason: "probe_group_match" };
784
+ }
785
+ } catch (error) {
786
+ writeDebugLine(
787
+ "msg.upload.thread_type.probe_error",
788
+ {
789
+ profile,
790
+ threadId,
791
+ message: toErrorText(error)
792
+ },
793
+ command
794
+ );
795
+ }
796
+ return { type: ThreadType.User, reason: "default_user" };
797
+ }
706
798
  function parseReaction(input) {
707
799
  const normalized = input.trim();
708
800
  if (EMOJI_REACTION_MAP[normalized]) {
@@ -2334,18 +2426,28 @@ msg.command("edit <msgId> <cliMsgId> <threadId> <message>").option("-g, --group"
2334
2426
  msg.command("upload <arg1> [arg2]").option("-u, --url <url>", "File URL (repeatable)", collectValues, []).option("-g, --group", "Upload in group").description("Upload and send file(s)").action(
2335
2427
  wrapAction(
2336
2428
  async (arg1, arg2, opts, command) => {
2337
- const { api } = await requireApi(command);
2429
+ const { api, profile } = await requireApi(command);
2338
2430
  const inputs = normalizeInputList(opts.url);
2339
2431
  const urlInputs = inputs.filter((entry) => isHttpUrl(entry));
2340
2432
  const localInputs = inputs.filter((entry) => !isHttpUrl(entry));
2341
2433
  const [threadId, file] = arg2 ? [arg2, arg1] : [arg1, void 0];
2434
+ const threadResolution = await resolveUploadThreadType(
2435
+ api,
2436
+ profile,
2437
+ threadId,
2438
+ opts.group,
2439
+ command
2440
+ );
2342
2441
  const normalizedFile = file ? normalizeMediaInput(file) : void 0;
2343
2442
  const localFiles = [normalizedFile, ...localInputs].filter(Boolean);
2344
2443
  writeDebugLine(
2345
2444
  "msg.upload.inputs",
2346
2445
  {
2347
2446
  threadId,
2348
- isGroup: Boolean(opts.group),
2447
+ explicitGroupFlag: Boolean(opts.group),
2448
+ isGroup: threadResolution.type === ThreadType.Group,
2449
+ threadType: threadResolution.type === ThreadType.Group ? "group" : "user",
2450
+ threadTypeReason: threadResolution.reason,
2349
2451
  localFiles,
2350
2452
  urlInputs
2351
2453
  },
@@ -2369,7 +2471,7 @@ msg.command("upload <arg1> [arg2]").option("-u, --url <url>", "File URL (repeata
2369
2471
  attachments
2370
2472
  },
2371
2473
  threadId,
2372
- asThreadType(opts.group)
2474
+ threadResolution.type
2373
2475
  )
2374
2476
  );
2375
2477
  output(response, false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzca",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "Open-source zca-compatible CLI to integrate Zalo with OpenClaw",
5
5
  "type": "module",
6
6
  "bin": {