openzca 0.1.45 → 0.1.46
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.
- package/README.md +7 -0
- package/dist/cli.js +99 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -126,6 +126,11 @@ For media debugging, grep these events in the debug log:
|
|
|
126
126
|
| `openzca group info <groupId>` | Get group details |
|
|
127
127
|
| `openzca group members <groupId>` | List members |
|
|
128
128
|
| `openzca group create <name> <members...>` | Create a group |
|
|
129
|
+
| `openzca group poll create <groupId>` | Create a poll (`--question`, repeatable `--option`, optional poll flags) |
|
|
130
|
+
| `openzca group poll detail <pollId>` | Get poll details |
|
|
131
|
+
| `openzca group poll vote <pollId>` | Vote on a poll with repeatable `--option <id>` |
|
|
132
|
+
| `openzca group poll lock <pollId>` | Close a poll |
|
|
133
|
+
| `openzca group poll share <pollId>` | Share a poll |
|
|
129
134
|
| `openzca group rename <groupId> <name>` | Rename group |
|
|
130
135
|
| `openzca group avatar <groupId> <file>` | Change group avatar |
|
|
131
136
|
| `openzca group settings <groupId>` | Update settings (`--lock-name`, `--sign-admin`, etc.) |
|
|
@@ -146,6 +151,8 @@ For media debugging, grep these events in the debug log:
|
|
|
146
151
|
| `openzca group leave <groupId>` | Leave group |
|
|
147
152
|
| `openzca group disperse <groupId>` | Disperse group |
|
|
148
153
|
|
|
154
|
+
Poll creation currently targets group threads only and maps to the existing `zca-js` group poll APIs. `group poll create` requires `--question` plus at least two `--option` values, and also supports `--multi`, `--allow-add-option`, `--hide-vote-preview`, `--anonymous`, and `--expire-ms`.
|
|
155
|
+
|
|
149
156
|
### friend — Friend management
|
|
150
157
|
|
|
151
158
|
| Command | Description |
|
package/dist/cli.js
CHANGED
|
@@ -578,6 +578,60 @@ async function assertFilesExist(files) {
|
|
|
578
578
|
}
|
|
579
579
|
}
|
|
580
580
|
|
|
581
|
+
// src/lib/group-poll.ts
|
|
582
|
+
function parsePositiveInteger(value, label) {
|
|
583
|
+
const normalized = value.trim();
|
|
584
|
+
if (!/^[1-9]\d*$/.test(normalized)) {
|
|
585
|
+
throw new Error(`${label} must be a positive integer.`);
|
|
586
|
+
}
|
|
587
|
+
const parsed = Number.parseInt(normalized, 10);
|
|
588
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
589
|
+
throw new Error(`${label} must be a positive integer.`);
|
|
590
|
+
}
|
|
591
|
+
return parsed;
|
|
592
|
+
}
|
|
593
|
+
function requireQuestion(value) {
|
|
594
|
+
const normalized = value?.trim() ?? "";
|
|
595
|
+
if (!normalized) {
|
|
596
|
+
throw new Error("Poll question is required.");
|
|
597
|
+
}
|
|
598
|
+
return normalized;
|
|
599
|
+
}
|
|
600
|
+
function normalizeOptions(values) {
|
|
601
|
+
const normalized = (values ?? []).map((value) => value.trim());
|
|
602
|
+
if (normalized.length < 2) {
|
|
603
|
+
throw new Error("Poll must include at least two options.");
|
|
604
|
+
}
|
|
605
|
+
for (let index = 0; index < normalized.length; index += 1) {
|
|
606
|
+
if (!normalized[index]) {
|
|
607
|
+
throw new Error(`Poll option ${index + 1} cannot be empty.`);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return normalized;
|
|
611
|
+
}
|
|
612
|
+
function parsePollId(value) {
|
|
613
|
+
return parsePositiveInteger(value, "Poll id");
|
|
614
|
+
}
|
|
615
|
+
function parsePollOptionIds(values) {
|
|
616
|
+
const optionIds = values ?? [];
|
|
617
|
+
if (optionIds.length === 0) {
|
|
618
|
+
throw new Error("Provide at least one option id.");
|
|
619
|
+
}
|
|
620
|
+
return optionIds.map((value) => parsePositiveInteger(value, "Option id"));
|
|
621
|
+
}
|
|
622
|
+
function buildCreatePollOptions(options) {
|
|
623
|
+
const expireMs = options.expireMs?.trim();
|
|
624
|
+
return {
|
|
625
|
+
question: requireQuestion(options.question),
|
|
626
|
+
options: normalizeOptions(options.option),
|
|
627
|
+
expiredTime: expireMs ? parsePositiveInteger(expireMs, "expire-ms") : void 0,
|
|
628
|
+
allowMultiChoices: Boolean(options.multi),
|
|
629
|
+
allowAddNewOption: Boolean(options.allowAddOption),
|
|
630
|
+
hideVotePreview: Boolean(options.hideVotePreview),
|
|
631
|
+
isAnonymous: Boolean(options.anonymous)
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
581
635
|
// src/lib/text-send.ts
|
|
582
636
|
import { ThreadType } from "zca-js";
|
|
583
637
|
|
|
@@ -3867,6 +3921,51 @@ group.command("create <name> <members...>").description("Create new group").acti
|
|
|
3867
3921
|
output(response, false);
|
|
3868
3922
|
})
|
|
3869
3923
|
);
|
|
3924
|
+
var groupPoll = group.command("poll").description("Group poll management");
|
|
3925
|
+
groupPoll.command("create <groupId>").requiredOption("-q, --question <text>", "Poll question").requiredOption("-o, --option <text>", "Poll option (repeatable)", collectValues, []).option("--multi", "Allow multiple choices").option("--allow-add-option", "Allow members to add new options").option("--hide-vote-preview", "Hide results until the member votes").option("--anonymous", "Hide voters").option("--expire-ms <ms>", "Poll expiration time in milliseconds").description("Create a poll in a group").action(
|
|
3926
|
+
wrapAction(
|
|
3927
|
+
async (groupId, opts, command) => {
|
|
3928
|
+
const pollOptions = buildCreatePollOptions(opts);
|
|
3929
|
+
const { api } = await requireApi(command);
|
|
3930
|
+
output(await api.createPoll(pollOptions, groupId), false);
|
|
3931
|
+
}
|
|
3932
|
+
)
|
|
3933
|
+
);
|
|
3934
|
+
groupPoll.command("detail <pollId>").description("Get poll detail").action(
|
|
3935
|
+
wrapAction(async (pollId, command) => {
|
|
3936
|
+
const normalizedPollId = parsePollId(pollId);
|
|
3937
|
+
const { api } = await requireApi(command);
|
|
3938
|
+
output(await api.getPollDetail(normalizedPollId), false);
|
|
3939
|
+
})
|
|
3940
|
+
);
|
|
3941
|
+
groupPoll.command("vote <pollId>").requiredOption("-o, --option <id>", "Poll option id (repeatable)", collectValues, []).description("Vote on a group poll").action(
|
|
3942
|
+
wrapAction(
|
|
3943
|
+
async (pollId, opts, command) => {
|
|
3944
|
+
const normalizedPollId = parsePollId(pollId);
|
|
3945
|
+
const optionIds = parsePollOptionIds(opts.option);
|
|
3946
|
+
const { api } = await requireApi(command);
|
|
3947
|
+
const response = await api.votePoll(
|
|
3948
|
+
normalizedPollId,
|
|
3949
|
+
optionIds.length === 1 ? optionIds[0] : optionIds
|
|
3950
|
+
);
|
|
3951
|
+
output(response, false);
|
|
3952
|
+
}
|
|
3953
|
+
)
|
|
3954
|
+
);
|
|
3955
|
+
groupPoll.command("lock <pollId>").description("Close a poll").action(
|
|
3956
|
+
wrapAction(async (pollId, command) => {
|
|
3957
|
+
const normalizedPollId = parsePollId(pollId);
|
|
3958
|
+
const { api } = await requireApi(command);
|
|
3959
|
+
output(await api.lockPoll(normalizedPollId), false);
|
|
3960
|
+
})
|
|
3961
|
+
);
|
|
3962
|
+
groupPoll.command("share <pollId>").description("Share a poll").action(
|
|
3963
|
+
wrapAction(async (pollId, command) => {
|
|
3964
|
+
const normalizedPollId = parsePollId(pollId);
|
|
3965
|
+
const { api } = await requireApi(command);
|
|
3966
|
+
output(await api.sharePoll(normalizedPollId), false);
|
|
3967
|
+
})
|
|
3968
|
+
);
|
|
3870
3969
|
group.command("rename <groupId> <name>").description("Rename group").action(
|
|
3871
3970
|
wrapAction(async (groupId, name, command) => {
|
|
3872
3971
|
const { api } = await requireApi(command);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzca",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
4
4
|
"description": "Open-source zca-compatible CLI to integrate Zalo with OpenClaw",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsup src/cli.ts --format esm --target node18 --out-dir dist --clean",
|
|
18
18
|
"dev": "tsx src/cli.ts",
|
|
19
|
+
"test": "tsx --test tests/*.test.ts",
|
|
19
20
|
"typecheck": "tsc -p tsconfig.json",
|
|
20
21
|
"lint": "tsc -p tsconfig.json --noEmit",
|
|
21
22
|
"prepublishOnly": "npm run build"
|