@qzhuli/qzhuli-cli 0.5.0 → 0.5.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.
- package/dist/cmd.js +223 -37
- package/package.json +1 -1
- package/skills/qzhuli-cli/SKILL.md +56 -76
package/dist/cmd.js
CHANGED
|
@@ -11203,6 +11203,7 @@ var commands = {
|
|
|
11203
11203
|
searchDesc: "Search user",
|
|
11204
11204
|
searchArgDesc: "Query string (default: Q\u52A9\u53F7)",
|
|
11205
11205
|
searchByUid: "Search by UID",
|
|
11206
|
+
searchByQNumber: "Search by Q\u52A9\u53F7",
|
|
11206
11207
|
addDesc: "Add friend by Q\u52A9\u53F7",
|
|
11207
11208
|
addArgDesc: "Q\u52A9\u53F7",
|
|
11208
11209
|
searchNotFound: "No user found with that Q\u52A9\u53F7.",
|
|
@@ -11216,6 +11217,7 @@ var commands = {
|
|
|
11216
11217
|
profileArgDesc: "Query string (default: nickname)",
|
|
11217
11218
|
profileByUid: "Search by UID",
|
|
11218
11219
|
profileByRemark: "Search by remark",
|
|
11220
|
+
profileByNickname: "Search by nickname",
|
|
11219
11221
|
pageOption: "Page number",
|
|
11220
11222
|
pageSizeOption: "Page size",
|
|
11221
11223
|
noFriends: "No friends or contacts found.",
|
|
@@ -11234,7 +11236,7 @@ var commands = {
|
|
|
11234
11236
|
},
|
|
11235
11237
|
message: {
|
|
11236
11238
|
desc: "Message operations",
|
|
11237
|
-
sendDesc: "Send a message to a conversation
|
|
11239
|
+
sendDesc: "Send a message to a conversation",
|
|
11238
11240
|
historyDesc: "View message history from a conversation",
|
|
11239
11241
|
fromOption: "Start from message ID",
|
|
11240
11242
|
directionOption: "Direction to pull",
|
|
@@ -11253,11 +11255,17 @@ var commands = {
|
|
|
11253
11255
|
profileArgDesc: "Conversation ID",
|
|
11254
11256
|
typeOption: "Conversation type (1=private, 2=group, auto-detect if omitted)",
|
|
11255
11257
|
profileSuccess: "Conversation details retrieved.",
|
|
11256
|
-
searchDesc: "Find
|
|
11257
|
-
searchArgDesc: "Query string (default:
|
|
11258
|
-
|
|
11258
|
+
searchDesc: "Find conversations by conversation ID, name, or user",
|
|
11259
|
+
searchArgDesc: "Query string (default: conversation ID)",
|
|
11260
|
+
searchByQNumber: "Search by user Q\u52A9\u53F7",
|
|
11261
|
+
searchByUid: "Search by user UID",
|
|
11262
|
+
searchByName: "Search by conversation name",
|
|
11263
|
+
searchByCid: "Search by conversation ID",
|
|
11259
11264
|
searchNotFound: "No conversations found with {name}.",
|
|
11260
|
-
searchSuccess: "Found {count} conversation(s) with {name}."
|
|
11265
|
+
searchSuccess: "Found {count} conversation(s) with {name}.",
|
|
11266
|
+
searchByIdSuccess: "Found conversation {id}.",
|
|
11267
|
+
searchByNameNotFound: 'No conversations found with name containing "{name}".',
|
|
11268
|
+
searchByNameSuccess: 'Found {count} conversation(s) with name containing "{name}".'
|
|
11261
11269
|
},
|
|
11262
11270
|
cache: {
|
|
11263
11271
|
desc: "Manage local cache",
|
|
@@ -11301,7 +11309,7 @@ __export(zh_exports, {
|
|
|
11301
11309
|
});
|
|
11302
11310
|
init_cjs_shims();
|
|
11303
11311
|
var cli2 = {
|
|
11304
|
-
banner: "qz \u2014 CLI for Q\u52A9\u7406
|
|
11312
|
+
banner: "qz \u2014 CLI for Q \u52A9\u7406\u3002"
|
|
11305
11313
|
};
|
|
11306
11314
|
var options2 = {
|
|
11307
11315
|
version: "\u8F93\u51FA\u7248\u672C\u53F7",
|
|
@@ -11320,7 +11328,7 @@ var auth2 = {
|
|
|
11320
11328
|
// 扫码登录
|
|
11321
11329
|
qrLogin: "\u626B\u7801\u767B\u5F55",
|
|
11322
11330
|
creatingQr: "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...",
|
|
11323
|
-
qrInstruction: "\u8BF7\u4F7F\
|
|
11331
|
+
qrInstruction: "\u8BF7\u4F7F\u7528 Q \u52A9\u7406\u624B\u673A App \u626B\u63CF\u4E0B\u65B9\u4E8C\u7EF4\u7801\u3002",
|
|
11324
11332
|
qrWaiting: "\u7B49\u5F85\u626B\u7801\u4E2D...",
|
|
11325
11333
|
qrLoginSuccess: "\u767B\u5F55\u6210\u529F\uFF01",
|
|
11326
11334
|
qrLoginSuccessWithName: "\u767B\u5F55\u6210\u529F\uFF01\u6B22\u8FCE\uFF0C{name}",
|
|
@@ -11348,12 +11356,13 @@ var commands2 = {
|
|
|
11348
11356
|
user: {
|
|
11349
11357
|
desc: "\u7528\u6237\u64CD\u4F5C",
|
|
11350
11358
|
searchDesc: "\u641C\u7D22\u7528\u6237",
|
|
11351
|
-
searchArgDesc: "\u67E5\u8BE2\u5185\u5BB9\uFF08\u9ED8\u8BA4\u6309 Q\u52A9\u53F7\uFF09",
|
|
11359
|
+
searchArgDesc: "\u67E5\u8BE2\u5185\u5BB9\uFF08\u9ED8\u8BA4\u6309 Q \u52A9\u53F7\uFF09",
|
|
11352
11360
|
searchByUid: "\u6309 UID \u641C\u7D22",
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11356
|
-
|
|
11361
|
+
searchByQNumber: "\u6309 Q \u52A9\u53F7\u641C\u7D22",
|
|
11362
|
+
addDesc: "\u901A\u8FC7 Q \u52A9\u53F7\u6DFB\u52A0\u597D\u53CB",
|
|
11363
|
+
addArgDesc: "Q \u52A9\u53F7",
|
|
11364
|
+
searchNotFound: "\u672A\u627E\u5230\u8BE5 Q \u52A9\u53F7\u7684\u7528\u6237\u3002",
|
|
11365
|
+
addNoAgentId: "\u7528\u6237\u6CA1\u6709\u52A9\u7406 ID\uFF0C\u65E0\u6CD5\u6DFB\u52A0\u3002",
|
|
11357
11366
|
addSuccess: "\u5DF2\u6DFB\u52A0\u597D\u53CB {name}\u3002"
|
|
11358
11367
|
},
|
|
11359
11368
|
friend: {
|
|
@@ -11363,6 +11372,7 @@ var commands2 = {
|
|
|
11363
11372
|
profileArgDesc: "\u67E5\u8BE2\u5185\u5BB9\uFF08\u9ED8\u8BA4\u6309\u6635\u79F0\uFF09",
|
|
11364
11373
|
profileByUid: "\u6309 UID \u641C\u7D22",
|
|
11365
11374
|
profileByRemark: "\u6309\u5907\u6CE8\u641C\u7D22",
|
|
11375
|
+
profileByNickname: "\u6309\u6635\u79F0\u641C\u7D22",
|
|
11366
11376
|
pageOption: "\u9875\u7801",
|
|
11367
11377
|
pageSizeOption: "\u6BCF\u9875\u6570\u91CF",
|
|
11368
11378
|
noFriends: "\u672A\u627E\u5230\u597D\u53CB\u6216\u8054\u7CFB\u4EBA\u3002",
|
|
@@ -11381,7 +11391,7 @@ var commands2 = {
|
|
|
11381
11391
|
},
|
|
11382
11392
|
message: {
|
|
11383
11393
|
desc: "\u6D88\u606F\u64CD\u4F5C",
|
|
11384
|
-
sendDesc: "\
|
|
11394
|
+
sendDesc: "\u5411\u4F1A\u8BDD\u53D1\u9001\u6D88\u606F",
|
|
11385
11395
|
historyDesc: "\u67E5\u770B\u4F1A\u8BDD\u6D88\u606F\u5386\u53F2",
|
|
11386
11396
|
fromOption: "\u8D77\u59CB\u6D88\u606F ID",
|
|
11387
11397
|
directionOption: "\u62C9\u53D6\u65B9\u5411",
|
|
@@ -11393,18 +11403,24 @@ var commands2 = {
|
|
|
11393
11403
|
limitOption: "\u6700\u5927\u4F1A\u8BDD\u6570",
|
|
11394
11404
|
offsetOption: "\u8DF3\u8FC7\u524D N \u6761\u4F1A\u8BDD",
|
|
11395
11405
|
createDesc: "\u521B\u5EFA\u4F1A\u8BDD",
|
|
11396
|
-
createArgDesc: "\u7528\
|
|
11397
|
-
createAgentIdOption: "\u52A9\
|
|
11406
|
+
createArgDesc: "\u7528\u6237 UID",
|
|
11407
|
+
createAgentIdOption: "\u52A9\u7406 ID",
|
|
11398
11408
|
createSuccess: "\u4F1A\u8BDD\u521B\u5EFA\u6210\u529F\u3002",
|
|
11399
11409
|
profileDesc: "\u67E5\u8BE2\u4F1A\u8BDD\u8BE6\u60C5",
|
|
11400
|
-
profileArgDesc: "\u4F1A\
|
|
11401
|
-
typeOption: "\u4F1A\u8BDD\u7C7B\u578B\uFF081
|
|
11410
|
+
profileArgDesc: "\u4F1A\u8BDD ID",
|
|
11411
|
+
typeOption: "\u4F1A\u8BDD\u7C7B\u578B\uFF081 = \u79C1\u804A, 2 = \u7FA4\u804A\uFF0C\u4E0D\u4F20\u81EA\u52A8\u5224\u65AD\uFF09",
|
|
11402
11412
|
profileSuccess: "\u5DF2\u83B7\u53D6\u4F1A\u8BDD\u8BE6\u60C5\u3002",
|
|
11403
|
-
searchDesc: "\u901A\
|
|
11404
|
-
searchArgDesc: "\u67E5\u8BE2\u5185\u5BB9\uFF08\u9ED8\u8BA4\u6309
|
|
11405
|
-
|
|
11413
|
+
searchDesc: "\u901A\u8FC7\u4F1A\u8BDD ID\u3001\u4F1A\u8BDD\u540D\u79F0\u6216\u7528\u6237\u67E5\u627E\u4F1A\u8BDD",
|
|
11414
|
+
searchArgDesc: "\u67E5\u8BE2\u5185\u5BB9\uFF08\u9ED8\u8BA4\u6309\u4F1A\u8BDD ID\uFF09",
|
|
11415
|
+
searchByQNumber: "\u6309\u7528\u6237 Q \u52A9\u53F7\u641C\u7D22",
|
|
11416
|
+
searchByUid: "\u6309\u7528\u6237 UID \u641C\u7D22",
|
|
11417
|
+
searchByName: "\u6309\u4F1A\u8BDD\u540D\u79F0\u641C\u7D22",
|
|
11418
|
+
searchByCid: "\u6309\u4F1A\u8BDD ID \u641C\u7D22",
|
|
11406
11419
|
searchNotFound: "\u672A\u627E\u5230\u4E0E {name} \u7684\u4F1A\u8BDD\u3002",
|
|
11407
|
-
searchSuccess: "\u627E\u5230\u4E0E {name} \u7684 {count} \u4E2A\u4F1A\u8BDD\u3002"
|
|
11420
|
+
searchSuccess: "\u627E\u5230\u4E0E {name} \u7684 {count} \u4E2A\u4F1A\u8BDD\u3002",
|
|
11421
|
+
searchByIdSuccess: "\u627E\u5230\u4F1A\u8BDD {id}\u3002",
|
|
11422
|
+
searchByNameNotFound: '\u672A\u627E\u5230\u540D\u79F0\u5305\u542B "{name}" \u7684\u4F1A\u8BDD\u3002',
|
|
11423
|
+
searchByNameSuccess: '\u627E\u5230 {count} \u4E2A\u540D\u79F0\u5305\u542B "{name}" \u7684\u4F1A\u8BDD\u3002'
|
|
11408
11424
|
},
|
|
11409
11425
|
cache: {
|
|
11410
11426
|
desc: "\u7BA1\u7406\u672C\u5730\u7F13\u5B58",
|
|
@@ -12557,7 +12573,96 @@ function profileToItem(profile) {
|
|
|
12557
12573
|
};
|
|
12558
12574
|
}
|
|
12559
12575
|
async function conversationSearchRun(factory, opts) {
|
|
12560
|
-
|
|
12576
|
+
if (opts.byCid || !opts.byQNumber && !opts.byUid && !opts.byName) {
|
|
12577
|
+
return searchByConversationId(factory, opts.query);
|
|
12578
|
+
}
|
|
12579
|
+
if (opts.byQNumber) {
|
|
12580
|
+
return searchByQNumber(factory, opts.query);
|
|
12581
|
+
}
|
|
12582
|
+
if (opts.byUid) {
|
|
12583
|
+
return searchByUid(factory, opts.query);
|
|
12584
|
+
}
|
|
12585
|
+
return searchByName(factory, opts.query);
|
|
12586
|
+
}
|
|
12587
|
+
async function searchByConversationId(factory, conversationId) {
|
|
12588
|
+
const profileResult = await factory.repos.conversation.getProfile(conversationId);
|
|
12589
|
+
if (!profileResult.ok) {
|
|
12590
|
+
return {
|
|
12591
|
+
status: "error",
|
|
12592
|
+
code: profileResult.code,
|
|
12593
|
+
message: profileResult.code === "AUTH_FAILED" /* AUTH_FAILED */ ? t("auth.notAuthenticated") : profileResult.message,
|
|
12594
|
+
data: null
|
|
12595
|
+
};
|
|
12596
|
+
}
|
|
12597
|
+
const profile = profileToItem(profileResult.data);
|
|
12598
|
+
const firstUser = profile.users[0];
|
|
12599
|
+
if (!firstUser) {
|
|
12600
|
+
return {
|
|
12601
|
+
status: "success",
|
|
12602
|
+
code: "NOT_FOUND" /* NOT_FOUND */,
|
|
12603
|
+
message: t("commands.conversation.searchNotFound"),
|
|
12604
|
+
data: null
|
|
12605
|
+
};
|
|
12606
|
+
}
|
|
12607
|
+
const result = {
|
|
12608
|
+
id: firstUser.id,
|
|
12609
|
+
uid: firstUser.uid,
|
|
12610
|
+
nickname: firstUser.nickname,
|
|
12611
|
+
conversations: [profile]
|
|
12612
|
+
};
|
|
12613
|
+
return {
|
|
12614
|
+
status: "success",
|
|
12615
|
+
code: "CONVERSATION_LIST" /* CONVERSATION_LIST */,
|
|
12616
|
+
message: t("commands.conversation.searchByIdSuccess").replace("{id}", conversationId),
|
|
12617
|
+
data: result
|
|
12618
|
+
};
|
|
12619
|
+
}
|
|
12620
|
+
async function searchByQNumber(factory, qNumber) {
|
|
12621
|
+
const userResult = await factory.repos.user.searchUserById(qNumber);
|
|
12622
|
+
if (!userResult.ok) {
|
|
12623
|
+
return {
|
|
12624
|
+
status: "error",
|
|
12625
|
+
code: userResult.code,
|
|
12626
|
+
message: userResult.code === "AUTH_FAILED" /* AUTH_FAILED */ ? t("auth.notAuthenticated") : userResult.message,
|
|
12627
|
+
data: null
|
|
12628
|
+
};
|
|
12629
|
+
}
|
|
12630
|
+
if (!userResult.data) {
|
|
12631
|
+
return {
|
|
12632
|
+
status: "error",
|
|
12633
|
+
code: "USER_NOT_FOUND_NEEDS_RESOLUTION" /* USER_NOT_FOUND_NEEDS_RESOLUTION */,
|
|
12634
|
+
message: t("messages.notFound"),
|
|
12635
|
+
data: null
|
|
12636
|
+
};
|
|
12637
|
+
}
|
|
12638
|
+
const targetId = userResult.data.id;
|
|
12639
|
+
const targetUid = userResult.data.uid;
|
|
12640
|
+
const nickname = userResult.data.nickname;
|
|
12641
|
+
const profilesResult = await factory.repos.conversation.searchByUid(targetUid);
|
|
12642
|
+
if (!profilesResult.ok || profilesResult.data.length === 0) {
|
|
12643
|
+
return {
|
|
12644
|
+
status: "success",
|
|
12645
|
+
code: "NOT_FOUND" /* NOT_FOUND */,
|
|
12646
|
+
message: t("commands.conversation.searchNotFound").replace("{name}", nickname),
|
|
12647
|
+
data: null
|
|
12648
|
+
};
|
|
12649
|
+
}
|
|
12650
|
+
const results = profilesResult.data.map(profileToItem);
|
|
12651
|
+
const result = {
|
|
12652
|
+
id: targetId,
|
|
12653
|
+
uid: targetUid,
|
|
12654
|
+
nickname,
|
|
12655
|
+
conversations: results
|
|
12656
|
+
};
|
|
12657
|
+
return {
|
|
12658
|
+
status: "success",
|
|
12659
|
+
code: "CONVERSATION_LIST" /* CONVERSATION_LIST */,
|
|
12660
|
+
message: t("commands.conversation.searchSuccess").replace("{name}", nickname).replace("{count}", String(results.length)),
|
|
12661
|
+
data: result
|
|
12662
|
+
};
|
|
12663
|
+
}
|
|
12664
|
+
async function searchByUid(factory, uid) {
|
|
12665
|
+
const userResult = await factory.repos.user.findUserById(uid);
|
|
12561
12666
|
if (!userResult.ok) {
|
|
12562
12667
|
return {
|
|
12563
12668
|
status: "error",
|
|
@@ -12600,6 +12705,72 @@ async function conversationSearchRun(factory, opts) {
|
|
|
12600
12705
|
data: result
|
|
12601
12706
|
};
|
|
12602
12707
|
}
|
|
12708
|
+
async function searchByName(factory, name) {
|
|
12709
|
+
const listResult = await factory.repos.conversation.queryAll({ limit: 0, offset: 0 });
|
|
12710
|
+
if (!listResult.ok) {
|
|
12711
|
+
return {
|
|
12712
|
+
status: "error",
|
|
12713
|
+
code: listResult.code,
|
|
12714
|
+
message: listResult.code === "AUTH_FAILED" /* AUTH_FAILED */ ? t("auth.notAuthenticated") : listResult.message,
|
|
12715
|
+
data: null
|
|
12716
|
+
};
|
|
12717
|
+
}
|
|
12718
|
+
const conversations3 = listResult.data ?? [];
|
|
12719
|
+
const matchedIds = conversations3.filter((c) => c.name?.includes(name)).map((c) => c.id);
|
|
12720
|
+
if (matchedIds.length === 0) {
|
|
12721
|
+
return {
|
|
12722
|
+
status: "success",
|
|
12723
|
+
code: "NOT_FOUND" /* NOT_FOUND */,
|
|
12724
|
+
message: t("commands.conversation.searchByNameNotFound").replace("{name}", name),
|
|
12725
|
+
data: null
|
|
12726
|
+
};
|
|
12727
|
+
}
|
|
12728
|
+
const profileResults = await Promise.all(
|
|
12729
|
+
matchedIds.map((convId) => factory.repos.conversation.getProfile(convId))
|
|
12730
|
+
);
|
|
12731
|
+
const profiles = profileResults.filter((r) => r.ok).map((r) => r.data);
|
|
12732
|
+
if (profiles.length === 0) {
|
|
12733
|
+
return {
|
|
12734
|
+
status: "success",
|
|
12735
|
+
code: "NOT_FOUND" /* NOT_FOUND */,
|
|
12736
|
+
message: t("commands.conversation.searchByNameNotFound").replace("{name}", name),
|
|
12737
|
+
data: null
|
|
12738
|
+
};
|
|
12739
|
+
}
|
|
12740
|
+
const items = profiles.map(profileToItem);
|
|
12741
|
+
const groupedByUid = /* @__PURE__ */ new Map();
|
|
12742
|
+
for (const item of items) {
|
|
12743
|
+
const primaryUser = item.users[0];
|
|
12744
|
+
if (!primaryUser) continue;
|
|
12745
|
+
const uid = primaryUser.uid;
|
|
12746
|
+
const existing = groupedByUid.get(uid);
|
|
12747
|
+
if (existing) {
|
|
12748
|
+
existing.conversations.push(item);
|
|
12749
|
+
} else {
|
|
12750
|
+
groupedByUid.set(uid, {
|
|
12751
|
+
id: primaryUser.id,
|
|
12752
|
+
uid,
|
|
12753
|
+
nickname: primaryUser.nickname,
|
|
12754
|
+
conversations: [item]
|
|
12755
|
+
});
|
|
12756
|
+
}
|
|
12757
|
+
}
|
|
12758
|
+
const results = [...groupedByUid.values()];
|
|
12759
|
+
if (results.length === 0) {
|
|
12760
|
+
return {
|
|
12761
|
+
status: "success",
|
|
12762
|
+
code: "NOT_FOUND" /* NOT_FOUND */,
|
|
12763
|
+
message: t("commands.conversation.searchByNameNotFound").replace("{name}", name),
|
|
12764
|
+
data: null
|
|
12765
|
+
};
|
|
12766
|
+
}
|
|
12767
|
+
return {
|
|
12768
|
+
status: "success",
|
|
12769
|
+
code: "CONVERSATION_LIST" /* CONVERSATION_LIST */,
|
|
12770
|
+
message: t("commands.conversation.searchByNameSuccess").replace("{name}", name).replace("{count}", String(results.length)),
|
|
12771
|
+
data: results
|
|
12772
|
+
};
|
|
12773
|
+
}
|
|
12603
12774
|
|
|
12604
12775
|
// src/commands/conversation/index.ts
|
|
12605
12776
|
function NewCmdConversation(factory) {
|
|
@@ -12622,10 +12793,18 @@ function NewCmdConversation(factory) {
|
|
|
12622
12793
|
const result = await conversationCreateRun(factory, { uid, agentId: opts.agentId });
|
|
12623
12794
|
handleCommand(result);
|
|
12624
12795
|
});
|
|
12625
|
-
cmd.command("search").description(t("commands.conversation.searchDesc")).argument("<query>", t("commands.conversation.searchArgDesc")).option("--uid", t("commands.conversation.searchByUid")).
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12796
|
+
cmd.command("search").description(t("commands.conversation.searchDesc")).argument("<query>", t("commands.conversation.searchArgDesc")).option("--qnumber", t("commands.conversation.searchByQNumber")).option("--uid", t("commands.conversation.searchByUid")).option("--name", t("commands.conversation.searchByName")).option("--cid", t("commands.conversation.searchByCid")).action(
|
|
12797
|
+
async (query, opts) => {
|
|
12798
|
+
const result = await conversationSearchRun(factory, {
|
|
12799
|
+
query,
|
|
12800
|
+
byQNumber: opts.qnumber,
|
|
12801
|
+
byUid: opts.uid,
|
|
12802
|
+
byName: opts.name,
|
|
12803
|
+
byCid: opts.cid
|
|
12804
|
+
});
|
|
12805
|
+
handleCommand(result);
|
|
12806
|
+
}
|
|
12807
|
+
);
|
|
12629
12808
|
return cmd;
|
|
12630
12809
|
}
|
|
12631
12810
|
|
|
@@ -12789,14 +12968,17 @@ function NewCmdFriend(factory) {
|
|
|
12789
12968
|
const result = await friendListRun(factory);
|
|
12790
12969
|
handleCommand(result);
|
|
12791
12970
|
});
|
|
12792
|
-
cmd.command("profile").description(t("commands.friend.profileDesc")).argument("<query>", t("commands.friend.profileArgDesc")).option("--uid", t("commands.friend.profileByUid")).option("--remark", t("commands.friend.profileByRemark")).
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12971
|
+
cmd.command("profile").description(t("commands.friend.profileDesc")).argument("<query>", t("commands.friend.profileArgDesc")).option("--uid", t("commands.friend.profileByUid")).option("--remark", t("commands.friend.profileByRemark")).option("--nickname", t("commands.friend.profileByNickname")).action(
|
|
12972
|
+
async (query, opts) => {
|
|
12973
|
+
const result = await friendProfileRun(factory, {
|
|
12974
|
+
query,
|
|
12975
|
+
byUid: opts.uid,
|
|
12976
|
+
byRemark: opts.remark,
|
|
12977
|
+
byNickname: opts.nickname
|
|
12978
|
+
});
|
|
12979
|
+
handleCommand(result);
|
|
12980
|
+
}
|
|
12981
|
+
);
|
|
12800
12982
|
return cmd;
|
|
12801
12983
|
}
|
|
12802
12984
|
|
|
@@ -13065,8 +13247,12 @@ async function userSearchRun(factory, opts) {
|
|
|
13065
13247
|
// src/commands/user/index.ts
|
|
13066
13248
|
function NewCmdUser(factory) {
|
|
13067
13249
|
const cmd = new import_commander8.Command("user").description(t("commands.user.desc"));
|
|
13068
|
-
cmd.command("search").description(t("commands.user.searchDesc")).argument("<query>", t("commands.user.searchArgDesc")).option("--uid", t("commands.user.searchByUid")).action(async (query, opts) => {
|
|
13069
|
-
const result = await userSearchRun(factory, {
|
|
13250
|
+
cmd.command("search").description(t("commands.user.searchDesc")).argument("<query>", t("commands.user.searchArgDesc")).option("--uid", t("commands.user.searchByUid")).option("--qnumber", t("commands.user.searchByQNumber")).action(async (query, opts) => {
|
|
13251
|
+
const result = await userSearchRun(factory, {
|
|
13252
|
+
query,
|
|
13253
|
+
byUid: opts.uid,
|
|
13254
|
+
byQNumber: opts.qnumber
|
|
13255
|
+
});
|
|
13070
13256
|
handleCommand(result);
|
|
13071
13257
|
});
|
|
13072
13258
|
cmd.command("add").description(t("commands.user.addDesc")).argument("<q-number>", t("commands.user.addArgDesc")).action(async (qNumber) => {
|
|
@@ -14921,7 +15107,7 @@ async function main() {
|
|
|
14921
15107
|
${t("cli.banner")}` : t("cli.banner");
|
|
14922
15108
|
program.addHelpText("beforeAll", `${banner}
|
|
14923
15109
|
`);
|
|
14924
|
-
program.name("qz").version(`v${"0.5.
|
|
15110
|
+
program.name("qz").version(`v${"0.5.2"}`, "-v, --version", t("options.version")).helpOption("-h, --help", t("options.help")).option("-q, --jq <expr>", t("options.jq")).option("--dry-run", t("options.dryRun"));
|
|
14925
15111
|
program.usage("<command> [subcommand] [options]");
|
|
14926
15112
|
program.hook("preAction", () => {
|
|
14927
15113
|
const opts = program.opts();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qzhuli-cli
|
|
3
3
|
description: Use when operating the QZhuli CLI (`qz`), including login, auth status, config, friends, relations, users, conversations, messages, cache management, JSON filtering, dry-run, command help, and interpreting test-environment banners or config files.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# QZhuli CLI
|
|
@@ -39,18 +39,11 @@ When ANY of the following applies, STOP and ask the user first:
|
|
|
39
39
|
- **Friend operations**: Before `user add`, show the target profile and confirm.
|
|
40
40
|
- **Relation changes**: Before `relation set`, show the current value and the new value, then confirm.
|
|
41
41
|
- **Cache clearing**: Before `cache clear`, confirm scope (all tables vs single table).
|
|
42
|
+
- **Message without conversation**: Before `message send`, check if a conversation with the target user exists. If not,
|
|
43
|
+
ask the user whether to create one first.
|
|
42
44
|
- **Any write operation** (`user add`, `relation set`, `conversation create`, `cache clear`): confirm
|
|
43
45
|
with user.
|
|
44
46
|
|
|
45
|
-
### Use --dry-run for Preview
|
|
46
|
-
|
|
47
|
-
Before any write operation the user hasn't explicitly confirmed, run with `--dry-run` first:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
qz --dry-run message send <id> "hello"
|
|
51
|
-
qz --dry-run relation set <uid> --remark "New Name"
|
|
52
|
-
```
|
|
53
|
-
|
|
54
47
|
### Least-Surprise Principle
|
|
55
48
|
|
|
56
49
|
- Never change a friend's remark without showing both old and new.
|
|
@@ -69,18 +62,12 @@ When sending messages, determine the role based on the user's wording:
|
|
|
69
62
|
|
|
70
63
|
The CLI uses 4 distinct ID types. **Using the wrong type will fail silently or hit the wrong target.**
|
|
71
64
|
|
|
72
|
-
| ID Type | Field Name | Format | Example | Used By
|
|
73
|
-
|
|
74
|
-
| Q助号 | `id` | Number, short | `10003` | `user add <q-number>`, `user search`, `conversation search` (
|
|
75
|
-
| UID | `uid` | 32-char hex string | `d5b6308e3abad6bc96573c58` | `relation get/set`, `friend profile --uid`, `user search --uid`, `conversation
|
|
76
|
-
| Conversation ID | `conversationId` | Base64-like long string | `9boGaR7iii2Jdjhmb5LSo37...` | `message send`, `message history`, `conversation profile`
|
|
77
|
-
| Agent ID | `agent.id` | Number | `5` | `conversation create --agent-id`
|
|
78
|
-
|
|
79
|
-
**Quick identification by format**:
|
|
80
|
-
|
|
81
|
-
- A short integer → Q助号
|
|
82
|
-
- A 32-char hex string → UID
|
|
83
|
-
- A long Base64-like string → conversationId
|
|
65
|
+
| ID Type | Field Name | Format | Example | Used By |
|
|
66
|
+
|-----------------|------------------|-------------------------|------------------------------|--------------------------------------------------------------------------------------------|
|
|
67
|
+
| Q助号 | `id` | Number, short | `10003` | `user add <q-number>`, `user search`, `conversation search` (with `--qnumber`) |
|
|
68
|
+
| UID | `uid` | 32-char hex string | `d5b6308e3abad6bc96573c58` | `relation get/set`, `friend profile --uid`, `user search --uid`, `conversation create` |
|
|
69
|
+
| Conversation ID | `conversationId` | Base64-like long string | `9boGaR7iii2Jdjhmb5LSo37...` | `message send`, `message history`, `conversation profile`, `conversation search` (default) |
|
|
70
|
+
| Agent ID | `agent.id` | Number | `5` | `conversation create --agent-id` |
|
|
84
71
|
|
|
85
72
|
**Common mistake**: Using UID for `message send` instead of conversationId. Always resolve via `conversation search` or
|
|
86
73
|
`conversation list` first.
|
|
@@ -116,37 +103,38 @@ qz --jq ".data" conversation list --limit 5
|
|
|
116
103
|
|
|
117
104
|
`--jq` is not full jq. Prefer simple paths: `.data`, `.data.uid`, `.data.links`.
|
|
118
105
|
|
|
119
|
-
Use `--dry-run` to preview without side effects. Wired through: output, HTTP API calls, IM WebSocket actions, auth
|
|
120
|
-
login/logout, and preference writes.
|
|
121
|
-
|
|
122
106
|
## Command Map
|
|
123
107
|
|
|
124
|
-
| Goal
|
|
125
|
-
|
|
126
|
-
| Check login
|
|
127
|
-
| QR login
|
|
128
|
-
| Clear credentials
|
|
129
|
-
| Show preferences
|
|
130
|
-
| Update preferences
|
|
131
|
-
| Search user (Q助号)
|
|
132
|
-
| Search user (
|
|
133
|
-
|
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
| Resolve profile (
|
|
137
|
-
| Resolve profile (
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
|
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
|
|
|
144
|
-
|
|
|
145
|
-
|
|
|
146
|
-
|
|
|
147
|
-
|
|
|
148
|
-
|
|
|
149
|
-
|
|
|
108
|
+
| Goal | Command |
|
|
109
|
+
|--------------------------------------|-----------------------------------------------------------------------------------------------|
|
|
110
|
+
| Check login | `qz auth status` |
|
|
111
|
+
| QR login | `qz auth login [--method qr-code]` |
|
|
112
|
+
| Clear credentials | `qz auth logout` |
|
|
113
|
+
| Show preferences | `qz config` |
|
|
114
|
+
| Update preferences | `qz config [--locale en\|zh] [--debug\|--no-debug]` |
|
|
115
|
+
| Search user (Q助号) | `qz user search <q-number>` |
|
|
116
|
+
| Search user (Q助号, explicit) | `qz user search <q-number> --qnumber` |
|
|
117
|
+
| Search user (UID) | `qz user search <uid> --uid` |
|
|
118
|
+
| Add friend (Q助号) | `qz user add <q-number>` |
|
|
119
|
+
| List friends | `qz friend list` |
|
|
120
|
+
| Resolve profile (nickname) | `qz friend profile <nickname>` |
|
|
121
|
+
| Resolve profile (nickname, explicit) | `qz friend profile <nickname> --nickname` |
|
|
122
|
+
| Resolve profile (UID) | `qz friend profile <uid> --uid` |
|
|
123
|
+
| Resolve profile (remark) | `qz friend profile <remark> --remark` |
|
|
124
|
+
| Read relation | `qz relation get <uid>` |
|
|
125
|
+
| Update relation | `qz relation set <uid> [-r, --remark <name>] [-t, --type <type>]` |
|
|
126
|
+
| List conversations | `qz conversation list [--limit <n>] [--offset <n>]` |
|
|
127
|
+
| Get conversation profile | `qz conversation profile <conversation-id> [--type <n>]` |
|
|
128
|
+
| Create conversation | `qz conversation create <uid> --agent-id <id>` |
|
|
129
|
+
| Search conversations (ID) | `qz conversation search <conversation-id>` |
|
|
130
|
+
| Search conversations (name) | `qz conversation search <name> --name` |
|
|
131
|
+
| Search conversations (Q助号) | `qz conversation search <q-number> --qnumber` |
|
|
132
|
+
| Search conversations (UID) | `qz conversation search <uid> --uid` |
|
|
133
|
+
| Send message | `qz message send <conversation-id> <content> [--role <n>]` |
|
|
134
|
+
| Read message history | `qz message history <conversation-id> [--from <id>] [--direction newer\|older] [--limit <n>]` |
|
|
135
|
+
| Sync cache | `qz cache sync` |
|
|
136
|
+
| Cache status | `qz cache status` |
|
|
137
|
+
| Clear cache | `qz cache clear [--table <name>]` |
|
|
150
138
|
|
|
151
139
|
Relation type values: `0=stranger`, `1=friend`, `2=family`, `3=colleague`.
|
|
152
140
|
|
|
@@ -160,8 +148,8 @@ Relation type values: `0=stranger`, `1=friend`, `2=family`, `3=colleague`.
|
|
|
160
148
|
|
|
161
149
|
### Update a Friend Relation
|
|
162
150
|
|
|
163
|
-
1. Resolve the exact `uid`
|
|
164
|
-
2. Show current value
|
|
151
|
+
1. Resolve the exact `uid` via `friend list` or `friend profile`.
|
|
152
|
+
2. Show current value, confirm the change.
|
|
165
153
|
3. Execute: `qz relation set <uid> --remark "New Name" --type 1`
|
|
166
154
|
4. Verify: `qz relation get <uid>`
|
|
167
155
|
|
|
@@ -176,18 +164,25 @@ Relation type values: `0=stranger`, `1=friend`, `2=family`, `3=colleague`.
|
|
|
176
164
|
### Find All Conversations with a User
|
|
177
165
|
|
|
178
166
|
```bash
|
|
179
|
-
qz conversation search
|
|
180
|
-
qz conversation search
|
|
167
|
+
qz conversation search <conversation-id> # default: by conversation ID
|
|
168
|
+
qz conversation search <name> --name # by conversation name
|
|
169
|
+
qz conversation search <q-number> --qnumber # by user Q助号
|
|
170
|
+
qz conversation search <uid> --uid # by user UID
|
|
181
171
|
```
|
|
182
172
|
|
|
183
|
-
Response includes `id
|
|
184
|
-
|
|
173
|
+
Response includes `id`, `uid`, and `conversations` with full profile data. Each entry contains `conversationId`,
|
|
174
|
+
`isGroup`, `users`, and `visitors`.
|
|
185
175
|
|
|
186
176
|
### Send a Message
|
|
187
177
|
|
|
188
178
|
1. Confirm auth: `qz auth status`
|
|
189
|
-
2.
|
|
190
|
-
|
|
179
|
+
2. **Check existing conversation**: If you have a `conversationId`, use `conversation search <conversation-id>`
|
|
180
|
+
directly. Otherwise, use `conversation search <q-number> --qnumber`, `conversation search <uid> --uid`,
|
|
181
|
+
or `conversation search <name> --name` to find conversations with the target user.
|
|
182
|
+
3. **Decision**:
|
|
183
|
+
- If conversations exist → pick the relevant `conversationId`.
|
|
184
|
+
- If no conversation exists → **ask the user first** whether to create one, then
|
|
185
|
+
`qz conversation create <uid> --agent-id <id>`.
|
|
191
186
|
4. Determine role: if the user says "以我的名义" / "帮我发给" / "替我发送" etc., add `--role 1`; otherwise omit (
|
|
192
187
|
defaults to Assistant).
|
|
193
188
|
5. Send: `qz message send <conversation-id> "message text"`
|
|
@@ -203,23 +198,7 @@ qz message history <conversation-id> --from <message-id> --direction newer --lim
|
|
|
203
198
|
|
|
204
199
|
### Pre-Sync Cache for Offline Speed
|
|
205
200
|
|
|
206
|
-
|
|
207
|
-
qz cache sync # fetch all data into local SQLite
|
|
208
|
-
qz cache status # verify record counts and sync time
|
|
209
|
-
qz conversation search 10000 # now instant from cache
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## Cache Architecture (Reference)
|
|
213
|
-
|
|
214
|
-
Read operations use a **Repository Pattern** with SQLite-backed caching (`~/.qzhuli-cli/cache.db`):
|
|
215
|
-
|
|
216
|
-
- **TTL**: conversations 30 min, contacts/relations 5 min, user profiles 1 hour
|
|
217
|
-
- **Incremental sync**: only fetches profiles for *new* conversations
|
|
218
|
-
- **Cache miss** → auto incremental sync (not full refetch)
|
|
219
|
-
- **Write operations** bypass cache, invalidate relevant entries
|
|
220
|
-
|
|
221
|
-
Tables: `conversations_index`, `conversation_profiles`, `contacts_cache`, `user_profiles`, `relations_cache`,
|
|
222
|
-
`messages_cache`.
|
|
201
|
+
Run `qz cache sync` before heavy read operations. Verify with `qz cache status`.
|
|
223
202
|
|
|
224
203
|
## Troubleshooting
|
|
225
204
|
|
|
@@ -231,6 +210,7 @@ Tables: `conversations_index`, `conversation_profiles`, `contacts_cache`, `user_
|
|
|
231
210
|
| Too much JSON | Use `--jq ".data"` or another simple dot path |
|
|
232
211
|
| Need no-op preview | Use `--dry-run` |
|
|
233
212
|
| Message send fails | Re-check `auth status`, verify conversationId via `conversation list` |
|
|
213
|
+
| Target has no conversation | Ask user to create one, then `conversation create <uid> --agent-id <id>` |
|
|
234
214
|
| Slow queries | Run `qz cache sync` first (incremental, fast), then retry |
|
|
235
215
|
| Cache corrupted | `qz cache clear` to reset, then retry (falls back to API) |
|
|
236
216
|
| Ambiguous search | `status: "needs_resolution"` — refine query with `--uid` or `--remark` flag |
|