@qzhuli/qzhuli-cli 0.5.4 → 0.5.6-beta.1
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 +344 -182
- package/package.json +1 -1
- package/skills/qzhuli-cli/SKILL.md +3 -1
package/dist/cmd.js
CHANGED
|
@@ -12302,37 +12302,46 @@ var import_commander2 = require("commander");
|
|
|
12302
12302
|
// src/commands/cache/clear.ts
|
|
12303
12303
|
init_cjs_shims();
|
|
12304
12304
|
async function cacheClearRun(factory, opts) {
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12305
|
+
try {
|
|
12306
|
+
if (opts.table) {
|
|
12307
|
+
switch (opts.table) {
|
|
12308
|
+
case "conversations":
|
|
12309
|
+
factory.repos.conversation.clear();
|
|
12310
|
+
break;
|
|
12311
|
+
case "contacts":
|
|
12312
|
+
factory.repos.contact.clear();
|
|
12313
|
+
break;
|
|
12314
|
+
case "users":
|
|
12315
|
+
factory.repos.user.clear();
|
|
12316
|
+
break;
|
|
12317
|
+
case "relations":
|
|
12318
|
+
factory.repos.relation.clear();
|
|
12319
|
+
break;
|
|
12320
|
+
case "messages":
|
|
12321
|
+
factory.repos.message.clear();
|
|
12322
|
+
break;
|
|
12323
|
+
default:
|
|
12324
|
+
return {
|
|
12325
|
+
status: "error",
|
|
12326
|
+
code: "INVALID_ARGUMENT" /* INVALID_ARGUMENT */,
|
|
12327
|
+
message: t("commands.cache.unknownTable").replace("{table}", opts.table),
|
|
12328
|
+
data: null
|
|
12329
|
+
};
|
|
12330
|
+
}
|
|
12331
|
+
} else {
|
|
12332
|
+
factory.repos.conversation.clear();
|
|
12333
|
+
factory.repos.contact.clear();
|
|
12334
|
+
factory.repos.user.clear();
|
|
12335
|
+
factory.repos.relation.clear();
|
|
12336
|
+
factory.repos.message.clear();
|
|
12329
12337
|
}
|
|
12330
|
-
}
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12338
|
+
} catch (error) {
|
|
12339
|
+
return {
|
|
12340
|
+
status: "error",
|
|
12341
|
+
code: "INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
12342
|
+
message: error instanceof Error ? error.message : "Failed to clear cache",
|
|
12343
|
+
data: null
|
|
12344
|
+
};
|
|
12336
12345
|
}
|
|
12337
12346
|
return {
|
|
12338
12347
|
status: "success",
|
|
@@ -12345,25 +12354,34 @@ async function cacheClearRun(factory, opts) {
|
|
|
12345
12354
|
// src/commands/cache/status.ts
|
|
12346
12355
|
init_cjs_shims();
|
|
12347
12356
|
async function cacheStatusRun(factory) {
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12357
|
+
try {
|
|
12358
|
+
const [convStatus, contactStatus] = await Promise.all([
|
|
12359
|
+
factory.repos.conversation.getStatus(),
|
|
12360
|
+
factory.repos.contact.getStatus()
|
|
12361
|
+
]);
|
|
12362
|
+
return {
|
|
12363
|
+
status: "success",
|
|
12364
|
+
code: "CONFIG_RETRIEVED" /* CONFIG_RETRIEVED */,
|
|
12365
|
+
message: "Cache status:",
|
|
12366
|
+
data: {
|
|
12367
|
+
conversations: {
|
|
12368
|
+
count: convStatus.count,
|
|
12369
|
+
lastSyncAt: convStatus.lastSyncAt ? new Date(convStatus.lastSyncAt).toISOString() : "never"
|
|
12370
|
+
},
|
|
12371
|
+
contacts: {
|
|
12372
|
+
count: contactStatus.count,
|
|
12373
|
+
lastSyncAt: contactStatus.lastSyncAt ? new Date(contactStatus.lastSyncAt).toISOString() : "never"
|
|
12374
|
+
}
|
|
12364
12375
|
}
|
|
12365
|
-
}
|
|
12366
|
-
}
|
|
12376
|
+
};
|
|
12377
|
+
} catch (error) {
|
|
12378
|
+
return {
|
|
12379
|
+
status: "error",
|
|
12380
|
+
code: "INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
12381
|
+
message: error instanceof Error ? error.message : "Failed to read cache status",
|
|
12382
|
+
data: null
|
|
12383
|
+
};
|
|
12384
|
+
}
|
|
12367
12385
|
}
|
|
12368
12386
|
|
|
12369
12387
|
// src/commands/cache/sync.ts
|
|
@@ -14369,33 +14387,53 @@ var SqliteContactRepository = class {
|
|
|
14369
14387
|
this.db = db;
|
|
14370
14388
|
}
|
|
14371
14389
|
async getLinksContacts() {
|
|
14372
|
-
|
|
14373
|
-
|
|
14374
|
-
|
|
14375
|
-
|
|
14376
|
-
|
|
14390
|
+
try {
|
|
14391
|
+
const rows = this.db.prepare(
|
|
14392
|
+
"SELECT owner_uid, data, cached_at FROM contacts_cache ORDER BY cached_at DESC LIMIT 1"
|
|
14393
|
+
).all();
|
|
14394
|
+
if (!rows || rows.length === 0) {
|
|
14395
|
+
return fail("NOT_FOUND" /* NOT_FOUND */, "Contacts not found in cache");
|
|
14396
|
+
}
|
|
14397
|
+
return ok(JSON.parse(rows[0].data));
|
|
14398
|
+
} catch (error) {
|
|
14399
|
+
return fail(
|
|
14400
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
14401
|
+
error instanceof Error ? error.message : "Failed to read contacts from cache"
|
|
14402
|
+
);
|
|
14377
14403
|
}
|
|
14378
|
-
return ok(JSON.parse(rows[0].data));
|
|
14379
14404
|
}
|
|
14380
14405
|
upsert(ownerUid, data) {
|
|
14381
|
-
|
|
14406
|
+
try {
|
|
14407
|
+
this.db.prepare("INSERT INTO contacts_cache (owner_uid, data, cached_at) VALUES (?, ?, ?)").run(ownerUid, JSON.stringify(data), Date.now());
|
|
14408
|
+
} catch {
|
|
14409
|
+
}
|
|
14382
14410
|
}
|
|
14383
14411
|
invalidate() {
|
|
14384
|
-
|
|
14412
|
+
try {
|
|
14413
|
+
this.db.exec("DELETE FROM contacts_cache");
|
|
14414
|
+
} catch {
|
|
14415
|
+
}
|
|
14385
14416
|
}
|
|
14386
14417
|
async sync() {
|
|
14387
14418
|
}
|
|
14388
14419
|
clear() {
|
|
14389
|
-
|
|
14390
|
-
|
|
14420
|
+
try {
|
|
14421
|
+
this.db.exec("DELETE FROM contacts_cache");
|
|
14422
|
+
this.db.exec("DELETE FROM cache_metadata WHERE key = 'last_sync_contacts'");
|
|
14423
|
+
} catch {
|
|
14424
|
+
}
|
|
14391
14425
|
}
|
|
14392
14426
|
async getStatus() {
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
|
|
14397
|
-
|
|
14398
|
-
|
|
14427
|
+
try {
|
|
14428
|
+
const count = this.db.prepare("SELECT COUNT(*) as c FROM contacts_cache").get();
|
|
14429
|
+
const meta = this.db.prepare("SELECT value FROM cache_metadata WHERE key = 'last_sync_contacts'").get();
|
|
14430
|
+
return {
|
|
14431
|
+
count: count.c,
|
|
14432
|
+
lastSyncAt: meta ? parseInt(meta.value, 10) : null
|
|
14433
|
+
};
|
|
14434
|
+
} catch {
|
|
14435
|
+
return { count: 0, lastSyncAt: null };
|
|
14436
|
+
}
|
|
14399
14437
|
}
|
|
14400
14438
|
};
|
|
14401
14439
|
var CachedContactRepository = class {
|
|
@@ -14408,17 +14446,23 @@ var CachedContactRepository = class {
|
|
|
14408
14446
|
remote;
|
|
14409
14447
|
ttlMs;
|
|
14410
14448
|
async getLinksContacts() {
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
|
|
14449
|
+
try {
|
|
14450
|
+
const cached = await this.local.getLinksContacts();
|
|
14451
|
+
if (cached.ok) {
|
|
14452
|
+
const status = await this.local.getStatus();
|
|
14453
|
+
if (status.lastSyncAt !== null && Date.now() - status.lastSyncAt < this.ttlMs) {
|
|
14454
|
+
return cached;
|
|
14455
|
+
}
|
|
14416
14456
|
}
|
|
14457
|
+
} catch {
|
|
14417
14458
|
}
|
|
14418
14459
|
const remote = await this.remote.getLinksContacts();
|
|
14419
14460
|
if (remote.ok) {
|
|
14420
|
-
|
|
14421
|
-
|
|
14461
|
+
try {
|
|
14462
|
+
this.local.upsert("", remote.data);
|
|
14463
|
+
this.local.db.prepare("INSERT OR REPLACE INTO cache_metadata (key, value) VALUES (?, ?)").run("last_sync_contacts", String(Date.now()));
|
|
14464
|
+
} catch {
|
|
14465
|
+
}
|
|
14422
14466
|
}
|
|
14423
14467
|
return remote;
|
|
14424
14468
|
}
|
|
@@ -14428,8 +14472,11 @@ var CachedContactRepository = class {
|
|
|
14428
14472
|
async sync() {
|
|
14429
14473
|
const result = await this.remote.getLinksContacts();
|
|
14430
14474
|
if (result.ok) {
|
|
14431
|
-
|
|
14432
|
-
|
|
14475
|
+
try {
|
|
14476
|
+
this.local.upsert("", result.data);
|
|
14477
|
+
this.local.db.prepare("INSERT OR REPLACE INTO cache_metadata (key, value) VALUES (?, ?)").run("last_sync_contacts", String(Date.now()));
|
|
14478
|
+
} catch {
|
|
14479
|
+
}
|
|
14433
14480
|
}
|
|
14434
14481
|
}
|
|
14435
14482
|
clear() {
|
|
@@ -14495,38 +14542,62 @@ var SqliteConversationRepository = class {
|
|
|
14495
14542
|
return Promise.resolve(ok([]));
|
|
14496
14543
|
}
|
|
14497
14544
|
getProfile(conversationId) {
|
|
14498
|
-
|
|
14499
|
-
|
|
14545
|
+
try {
|
|
14546
|
+
const row = this.db.prepare("SELECT data FROM conversation_profiles WHERE conversation_id = ?").get(conversationId);
|
|
14547
|
+
if (!row) {
|
|
14548
|
+
return Promise.resolve(
|
|
14549
|
+
fail("NOT_FOUND" /* NOT_FOUND */, "Conversation profile not found in cache")
|
|
14550
|
+
);
|
|
14551
|
+
}
|
|
14552
|
+
return Promise.resolve(ok(JSON.parse(row.data)));
|
|
14553
|
+
} catch (error) {
|
|
14500
14554
|
return Promise.resolve(
|
|
14501
|
-
fail(
|
|
14555
|
+
fail(
|
|
14556
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
14557
|
+
error instanceof Error ? error.message : "Failed to read conversation from cache"
|
|
14558
|
+
)
|
|
14502
14559
|
);
|
|
14503
14560
|
}
|
|
14504
|
-
return Promise.resolve(ok(JSON.parse(row.data)));
|
|
14505
14561
|
}
|
|
14506
14562
|
searchByUid(uid) {
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14563
|
+
try {
|
|
14564
|
+
const rows = this.db.prepare(
|
|
14565
|
+
"SELECT data FROM conversation_profiles WHERE user_ids LIKE ? OR user_ids LIKE ? OR user_ids LIKE ? OR user_ids = ?"
|
|
14566
|
+
).all(`%${uid},%`, `%,${uid},%`, `%,${uid}`, uid);
|
|
14567
|
+
const results = rows.map((r) => JSON.parse(r.data));
|
|
14568
|
+
return Promise.resolve(ok(results));
|
|
14569
|
+
} catch (error) {
|
|
14570
|
+
return Promise.resolve(
|
|
14571
|
+
fail(
|
|
14572
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
14573
|
+
error instanceof Error ? error.message : "Failed to search conversations in cache"
|
|
14574
|
+
)
|
|
14575
|
+
);
|
|
14576
|
+
}
|
|
14512
14577
|
}
|
|
14513
14578
|
upsertProfile(conversationId, profile) {
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
14519
|
-
|
|
14579
|
+
try {
|
|
14580
|
+
const user_ids = profile.users.map((u) => u.uid).join(",");
|
|
14581
|
+
const cached_at = Date.now();
|
|
14582
|
+
const data = JSON.stringify(profile);
|
|
14583
|
+
this.db.prepare(
|
|
14584
|
+
"INSERT INTO conversation_profiles (conversation_id, data, user_ids, cached_at) VALUES (?, ?, ?, ?) ON CONFLICT(conversation_id) DO UPDATE SET data=?, user_ids=?, cached_at=?"
|
|
14585
|
+
).run(conversationId, data, user_ids, cached_at, data, user_ids, cached_at);
|
|
14586
|
+
} catch {
|
|
14587
|
+
}
|
|
14520
14588
|
}
|
|
14521
14589
|
// MARK: Conversation Index (for incremental sync)
|
|
14522
14590
|
upsertIndex(conv) {
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14591
|
+
try {
|
|
14592
|
+
const members = JSON.stringify(conv.cids);
|
|
14593
|
+
const nicks = conv.nicks ? JSON.stringify(conv.nicks) : null;
|
|
14594
|
+
const im_version = conv.version;
|
|
14595
|
+
const cached_at = Date.now();
|
|
14596
|
+
this.db.prepare(
|
|
14597
|
+
"INSERT INTO conversations_index (conversation_id, im_version, members, nicks, cached_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(conversation_id) DO UPDATE SET im_version=?, members=?, nicks=?, cached_at=?"
|
|
14598
|
+
).run(conv.id, im_version, members, nicks, cached_at, im_version, members, nicks, cached_at);
|
|
14599
|
+
} catch {
|
|
14600
|
+
}
|
|
14530
14601
|
}
|
|
14531
14602
|
getIndexById(conversationId) {
|
|
14532
14603
|
return this.db.prepare(
|
|
@@ -14534,34 +14605,51 @@ var SqliteConversationRepository = class {
|
|
|
14534
14605
|
).get(conversationId);
|
|
14535
14606
|
}
|
|
14536
14607
|
getAllIds() {
|
|
14537
|
-
|
|
14538
|
-
|
|
14608
|
+
try {
|
|
14609
|
+
const rows = this.db.prepare("SELECT conversation_id FROM conversations_index").all();
|
|
14610
|
+
return rows.map((r) => r.conversation_id);
|
|
14611
|
+
} catch {
|
|
14612
|
+
return [];
|
|
14613
|
+
}
|
|
14539
14614
|
}
|
|
14540
14615
|
deleteStale(conversationIds) {
|
|
14541
|
-
|
|
14542
|
-
|
|
14543
|
-
|
|
14544
|
-
|
|
14616
|
+
try {
|
|
14617
|
+
if (conversationIds.length === 0) return;
|
|
14618
|
+
const placeholders = conversationIds.map(() => "?").join(",");
|
|
14619
|
+
this.db.prepare(`DELETE FROM conversation_profiles WHERE conversation_id NOT IN (${placeholders})`).run(...conversationIds);
|
|
14620
|
+
this.db.prepare(`DELETE FROM conversations_index WHERE conversation_id NOT IN (${placeholders})`).run(...conversationIds);
|
|
14621
|
+
} catch {
|
|
14622
|
+
}
|
|
14545
14623
|
}
|
|
14546
14624
|
invalidate(conversationId) {
|
|
14547
|
-
|
|
14548
|
-
|
|
14625
|
+
try {
|
|
14626
|
+
this.db.prepare("DELETE FROM conversation_profiles WHERE conversation_id = ?").run(conversationId);
|
|
14627
|
+
this.db.prepare("DELETE FROM conversations_index WHERE conversation_id = ?").run(conversationId);
|
|
14628
|
+
} catch {
|
|
14629
|
+
}
|
|
14549
14630
|
}
|
|
14550
14631
|
sync() {
|
|
14551
14632
|
return Promise.resolve();
|
|
14552
14633
|
}
|
|
14553
14634
|
clear() {
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14635
|
+
try {
|
|
14636
|
+
this.db.exec("DELETE FROM conversation_profiles");
|
|
14637
|
+
this.db.exec("DELETE FROM conversations_index");
|
|
14638
|
+
this.db.exec("DELETE FROM cache_metadata WHERE key = 'last_sync_conversations'");
|
|
14639
|
+
} catch {
|
|
14640
|
+
}
|
|
14557
14641
|
}
|
|
14558
14642
|
getStatus() {
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14643
|
+
try {
|
|
14644
|
+
const count = this.db.prepare("SELECT COUNT(*) as c FROM conversation_profiles").get();
|
|
14645
|
+
const meta = this.db.prepare("SELECT value FROM cache_metadata WHERE key = 'last_sync_conversations'").get();
|
|
14646
|
+
return Promise.resolve({
|
|
14647
|
+
count: count.c,
|
|
14648
|
+
lastSyncAt: meta ? parseInt(meta.value, 10) : null
|
|
14649
|
+
});
|
|
14650
|
+
} catch {
|
|
14651
|
+
return Promise.resolve({ count: 0, lastSyncAt: null });
|
|
14652
|
+
}
|
|
14565
14653
|
}
|
|
14566
14654
|
};
|
|
14567
14655
|
var CachedConversationRepository = class {
|
|
@@ -14668,50 +14756,66 @@ var SqliteMessageRepository = class {
|
|
|
14668
14756
|
this.db = db;
|
|
14669
14757
|
}
|
|
14670
14758
|
async pullMessages(conversationId, options3) {
|
|
14671
|
-
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
|
|
14676
|
-
if (
|
|
14677
|
-
|
|
14678
|
-
|
|
14679
|
-
|
|
14680
|
-
|
|
14681
|
-
|
|
14759
|
+
try {
|
|
14760
|
+
const limit = options3?.limit ?? 50;
|
|
14761
|
+
const fromId = options3?.fromMessageId;
|
|
14762
|
+
let sql = "SELECT message_id, data FROM messages_cache WHERE conversation_id = ?";
|
|
14763
|
+
const params = [conversationId];
|
|
14764
|
+
if (fromId) {
|
|
14765
|
+
if (options3?.direction === "newer") {
|
|
14766
|
+
sql += " AND message_id > ?";
|
|
14767
|
+
params.push(fromId);
|
|
14768
|
+
} else {
|
|
14769
|
+
sql += " AND message_id < ?";
|
|
14770
|
+
params.push(fromId);
|
|
14771
|
+
}
|
|
14682
14772
|
}
|
|
14773
|
+
sql += " ORDER BY message_id DESC LIMIT ?";
|
|
14774
|
+
params.push(limit);
|
|
14775
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
14776
|
+
if (rows.length === 0) {
|
|
14777
|
+
return fail("NOT_FOUND" /* NOT_FOUND */, "Messages not found in cache");
|
|
14778
|
+
}
|
|
14779
|
+
return ok({
|
|
14780
|
+
messages: rows.map((r) => JSON.parse(r.data)),
|
|
14781
|
+
finished: rows.length < limit,
|
|
14782
|
+
lastId: rows[rows.length - 1]?.message_id ?? ""
|
|
14783
|
+
});
|
|
14784
|
+
} catch (error) {
|
|
14785
|
+
return fail(
|
|
14786
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
14787
|
+
error instanceof Error ? error.message : "Failed to read messages from cache"
|
|
14788
|
+
);
|
|
14683
14789
|
}
|
|
14684
|
-
sql += " ORDER BY message_id DESC LIMIT ?";
|
|
14685
|
-
params.push(limit);
|
|
14686
|
-
const rows = this.db.prepare(sql).all(...params);
|
|
14687
|
-
if (rows.length === 0) {
|
|
14688
|
-
return fail("NOT_FOUND" /* NOT_FOUND */, "Messages not found in cache");
|
|
14689
|
-
}
|
|
14690
|
-
return ok({
|
|
14691
|
-
messages: rows.map((r) => JSON.parse(r.data)),
|
|
14692
|
-
finished: rows.length < limit,
|
|
14693
|
-
lastId: rows[rows.length - 1]?.message_id ?? ""
|
|
14694
|
-
});
|
|
14695
14790
|
}
|
|
14696
14791
|
upsert(conversationId, messageId, data) {
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
|
|
14706
|
-
|
|
14792
|
+
try {
|
|
14793
|
+
this.db.prepare(
|
|
14794
|
+
"INSERT INTO messages_cache (conversation_id, message_id, data, cached_at) VALUES (?, ?, ?, ?) ON CONFLICT(conversation_id, message_id) DO UPDATE SET data=?, cached_at=?"
|
|
14795
|
+
).run(
|
|
14796
|
+
conversationId,
|
|
14797
|
+
messageId,
|
|
14798
|
+
JSON.stringify(data),
|
|
14799
|
+
Date.now(),
|
|
14800
|
+
JSON.stringify(data),
|
|
14801
|
+
Date.now()
|
|
14802
|
+
);
|
|
14803
|
+
} catch {
|
|
14804
|
+
}
|
|
14707
14805
|
}
|
|
14708
14806
|
invalidate(conversationId) {
|
|
14709
|
-
|
|
14807
|
+
try {
|
|
14808
|
+
this.db.prepare("DELETE FROM messages_cache WHERE conversation_id = ?").run(conversationId);
|
|
14809
|
+
} catch {
|
|
14810
|
+
}
|
|
14710
14811
|
}
|
|
14711
14812
|
async sync(_conversationId) {
|
|
14712
14813
|
}
|
|
14713
14814
|
clear() {
|
|
14714
|
-
|
|
14815
|
+
try {
|
|
14816
|
+
this.db.exec("DELETE FROM messages_cache");
|
|
14817
|
+
} catch {
|
|
14818
|
+
}
|
|
14715
14819
|
}
|
|
14716
14820
|
};
|
|
14717
14821
|
var CachedMessageRepository = class {
|
|
@@ -14777,22 +14881,38 @@ var SqliteRelationRepository = class {
|
|
|
14777
14881
|
this.db = db;
|
|
14778
14882
|
}
|
|
14779
14883
|
async getLinkNameType(friendUid) {
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
14884
|
+
try {
|
|
14885
|
+
const row = this.db.prepare("SELECT name, type, cached_at FROM relations_cache WHERE friend_uid = ?").get(friendUid);
|
|
14886
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "Relation not found in cache");
|
|
14887
|
+
return ok({ name: row.name, type: row.type });
|
|
14888
|
+
} catch (error) {
|
|
14889
|
+
return fail(
|
|
14890
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
14891
|
+
error instanceof Error ? error.message : "Failed to read relation from cache"
|
|
14892
|
+
);
|
|
14893
|
+
}
|
|
14783
14894
|
}
|
|
14784
14895
|
upsert(friendUid, name, type) {
|
|
14785
|
-
|
|
14786
|
-
|
|
14787
|
-
|
|
14896
|
+
try {
|
|
14897
|
+
this.db.prepare(
|
|
14898
|
+
"INSERT OR REPLACE INTO relations_cache (friend_uid, name, type, cached_at) VALUES (?, ?, ?, ?)"
|
|
14899
|
+
).run(friendUid, name, type, Date.now());
|
|
14900
|
+
} catch {
|
|
14901
|
+
}
|
|
14788
14902
|
}
|
|
14789
14903
|
invalidate(friendUid) {
|
|
14790
|
-
|
|
14904
|
+
try {
|
|
14905
|
+
this.db.prepare("DELETE FROM relations_cache WHERE friend_uid = ?").run(friendUid);
|
|
14906
|
+
} catch {
|
|
14907
|
+
}
|
|
14791
14908
|
}
|
|
14792
14909
|
async sync() {
|
|
14793
14910
|
}
|
|
14794
14911
|
clear() {
|
|
14795
|
-
|
|
14912
|
+
try {
|
|
14913
|
+
this.db.exec("DELETE FROM relations_cache");
|
|
14914
|
+
} catch {
|
|
14915
|
+
}
|
|
14796
14916
|
}
|
|
14797
14917
|
};
|
|
14798
14918
|
var CachedRelationRepository = class {
|
|
@@ -14805,13 +14925,19 @@ var CachedRelationRepository = class {
|
|
|
14805
14925
|
remote;
|
|
14806
14926
|
ttlMs;
|
|
14807
14927
|
async getLinkNameType(friendUid) {
|
|
14808
|
-
|
|
14809
|
-
|
|
14810
|
-
|
|
14928
|
+
try {
|
|
14929
|
+
const row = this.local.db.prepare("SELECT name, type, cached_at FROM relations_cache WHERE friend_uid = ?").get(friendUid);
|
|
14930
|
+
if (row && Date.now() - row.cached_at < this.ttlMs) {
|
|
14931
|
+
return ok({ name: row.name, type: row.type });
|
|
14932
|
+
}
|
|
14933
|
+
} catch {
|
|
14811
14934
|
}
|
|
14812
14935
|
const remote = await this.remote.getLinkNameType(friendUid);
|
|
14813
14936
|
if (remote.ok) {
|
|
14814
|
-
|
|
14937
|
+
try {
|
|
14938
|
+
this.local.upsert(friendUid, remote.data.name, remote.data.type);
|
|
14939
|
+
} catch {
|
|
14940
|
+
}
|
|
14815
14941
|
}
|
|
14816
14942
|
return remote;
|
|
14817
14943
|
}
|
|
@@ -14938,37 +15064,67 @@ var SqliteUserRepository = class {
|
|
|
14938
15064
|
this.db = db;
|
|
14939
15065
|
}
|
|
14940
15066
|
async findUserById(id) {
|
|
14941
|
-
|
|
14942
|
-
|
|
14943
|
-
|
|
15067
|
+
try {
|
|
15068
|
+
const row = this.db.prepare("SELECT data FROM user_profiles WHERE uid = ?").get(id);
|
|
15069
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "User not found in cache");
|
|
15070
|
+
return ok(JSON.parse(row.data));
|
|
15071
|
+
} catch (error) {
|
|
15072
|
+
return fail(
|
|
15073
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
15074
|
+
error instanceof Error ? error.message : "Failed to read user from cache"
|
|
15075
|
+
);
|
|
15076
|
+
}
|
|
14944
15077
|
}
|
|
14945
15078
|
async searchUserById(id) {
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
15079
|
+
try {
|
|
15080
|
+
const row = this.db.prepare("SELECT data FROM user_profiles WHERE uid = ?").get(id);
|
|
15081
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "User not found in cache");
|
|
15082
|
+
const data = JSON.parse(row.data);
|
|
15083
|
+
return ok({
|
|
15084
|
+
id: data.id,
|
|
15085
|
+
uid: data.uid,
|
|
15086
|
+
nickname: data.nickname,
|
|
15087
|
+
avatar: data.avatar,
|
|
15088
|
+
agent: data.agent
|
|
15089
|
+
});
|
|
15090
|
+
} catch (error) {
|
|
15091
|
+
return fail(
|
|
15092
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
15093
|
+
error instanceof Error ? error.message : "Failed to search user in cache"
|
|
15094
|
+
);
|
|
15095
|
+
}
|
|
14956
15096
|
}
|
|
14957
15097
|
async getUserAgentProfile(friendUid, _agentId) {
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
15098
|
+
try {
|
|
15099
|
+
const row = this.db.prepare("SELECT data FROM user_profiles WHERE uid = ?").get(friendUid);
|
|
15100
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "User profile not found in cache");
|
|
15101
|
+
return ok(JSON.parse(row.data));
|
|
15102
|
+
} catch (error) {
|
|
15103
|
+
return fail(
|
|
15104
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
15105
|
+
error instanceof Error ? error.message : "Failed to read user profile from cache"
|
|
15106
|
+
);
|
|
15107
|
+
}
|
|
14961
15108
|
}
|
|
14962
15109
|
upsert(uid, data) {
|
|
14963
|
-
|
|
15110
|
+
try {
|
|
15111
|
+
this.db.prepare("INSERT OR REPLACE INTO user_profiles (uid, data, cached_at) VALUES (?, ?, ?)").run(uid, JSON.stringify(data), Date.now());
|
|
15112
|
+
} catch {
|
|
15113
|
+
}
|
|
14964
15114
|
}
|
|
14965
15115
|
invalidate(uid) {
|
|
14966
|
-
|
|
15116
|
+
try {
|
|
15117
|
+
this.db.prepare("DELETE FROM user_profiles WHERE uid = ?").run(uid);
|
|
15118
|
+
} catch {
|
|
15119
|
+
}
|
|
14967
15120
|
}
|
|
14968
15121
|
async sync() {
|
|
14969
15122
|
}
|
|
14970
15123
|
clear() {
|
|
14971
|
-
|
|
15124
|
+
try {
|
|
15125
|
+
this.db.exec("DELETE FROM user_profiles");
|
|
15126
|
+
} catch {
|
|
15127
|
+
}
|
|
14972
15128
|
}
|
|
14973
15129
|
};
|
|
14974
15130
|
var CachedUserRepository = class {
|
|
@@ -15015,13 +15171,19 @@ var CachedUserRepository = class {
|
|
|
15015
15171
|
);
|
|
15016
15172
|
}
|
|
15017
15173
|
async fetchWithCache(uid, fetch2, store) {
|
|
15018
|
-
|
|
15019
|
-
|
|
15020
|
-
|
|
15174
|
+
try {
|
|
15175
|
+
const row = this.local.db.prepare("SELECT data, cached_at FROM user_profiles WHERE uid = ?").get(uid);
|
|
15176
|
+
if (row && Date.now() - row.cached_at < this.ttlMs) {
|
|
15177
|
+
return ok(JSON.parse(row.data));
|
|
15178
|
+
}
|
|
15179
|
+
} catch (error) {
|
|
15021
15180
|
}
|
|
15022
15181
|
const remote = await fetch2();
|
|
15023
15182
|
if (remote.ok) {
|
|
15024
|
-
|
|
15183
|
+
try {
|
|
15184
|
+
store(remote.data);
|
|
15185
|
+
} catch {
|
|
15186
|
+
}
|
|
15025
15187
|
}
|
|
15026
15188
|
return remote;
|
|
15027
15189
|
}
|
|
@@ -15143,7 +15305,7 @@ async function main() {
|
|
|
15143
15305
|
${t("cli.banner")}` : t("cli.banner");
|
|
15144
15306
|
program.addHelpText("beforeAll", `${banner}
|
|
15145
15307
|
`);
|
|
15146
|
-
program.name("qz").version(`v${"0.5.
|
|
15308
|
+
program.name("qz").version(`v${"0.5.6-beta.1"}`, "-v, --version", t("options.version")).helpOption("-h, --help", t("options.help")).option("-q, --jq <expr>", t("options.jq")).option("--dry-run", t("options.dryRun"));
|
|
15147
15309
|
program.usage("<command> [subcommand] [options]");
|
|
15148
15310
|
program.hook("preAction", () => {
|
|
15149
15311
|
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.3
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# QZhuli CLI
|
|
@@ -127,6 +127,7 @@ qz --jq ".data" conversation list --limit 5
|
|
|
127
127
|
| Get conversation profile | `qz conversation profile <conversation-id> [--type <n>]` |
|
|
128
128
|
| Create conversation | `qz conversation create <uid> --agent-id <id>` |
|
|
129
129
|
| Search conversations (ID) | `qz conversation search <conversation-id>` |
|
|
130
|
+
| Search conversations (CID) | `qz conversation search <cid> --cid` |
|
|
130
131
|
| Search conversations (name) | `qz conversation search <name> --name` |
|
|
131
132
|
| Search conversations (Q助号) | `qz conversation search <q-number> --qnumber` |
|
|
132
133
|
| Search conversations (UID) | `qz conversation search <uid> --uid` |
|
|
@@ -165,6 +166,7 @@ Relation type values: `0=stranger`, `1=friend`, `2=family`, `3=colleague`.
|
|
|
165
166
|
|
|
166
167
|
```bash
|
|
167
168
|
qz conversation search <conversation-id> # default: by conversation ID
|
|
169
|
+
qz conversation search <cid> --cid # by user CID
|
|
168
170
|
qz conversation search <name> --name # by conversation name
|
|
169
171
|
qz conversation search <q-number> --qnumber # by user Q助号
|
|
170
172
|
qz conversation search <uid> --uid # by user UID
|