@pmate/cli 0.24.44 → 0.25.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/index.d.ts CHANGED
@@ -571,6 +571,7 @@ type CollectCommandArgs = {
571
571
  endpoint?: string;
572
572
  thread: string;
573
573
  text: string;
574
+ dryRun: boolean;
574
575
  };
575
576
  type ChatRoomCommonArgs = {
576
577
  type: Command.ChatRoom;
package/dist/index.js CHANGED
@@ -16179,7 +16179,11 @@ var CollectCommandHandler = class {
16179
16179
  if (!thread) {
16180
16180
  throw new Error(`Thread not found: ${args.thread}`);
16181
16181
  }
16182
- await this.sendReplyViaConversation(targetPage, thread, args.text);
16182
+ const result = await this.sendReplyViaConversation(targetPage, thread, args.text, args.dryRun);
16183
+ if (args.dryRun) {
16184
+ ui.plain(JSON.stringify({ source: target.sourceKey, thread: thread.name, ...result }, null, 2));
16185
+ return;
16186
+ }
16183
16187
  ui.success("im1 reply sent", { source: target.sourceKey, thread: thread.name });
16184
16188
  } catch (error) {
16185
16189
  const message = error instanceof Error ? error.message : String(error);
@@ -16412,14 +16416,15 @@ var CollectCommandHandler = class {
16412
16416
  await session.detach().catch(() => void 0);
16413
16417
  }
16414
16418
  }
16415
- async sendReplyViaConversation(page, thread, text) {
16419
+ async sendReplyViaConversation(page, thread, text, dryRun) {
16416
16420
  const result = await this.evaluateInPage(
16417
16421
  page,
16418
- buildSendMessageExpr(thread.conversationId, text)
16422
+ buildSendMessageExpr(thread.conversationId, text, dryRun)
16419
16423
  );
16420
16424
  if (!result?.ok) {
16421
16425
  throw new Error(result?.reason || "Send failed");
16422
16426
  }
16427
+ return result;
16423
16428
  }
16424
16429
  };
16425
16430
  async function archiveMessageImages(rootDir, sourceKey, threadKey, messages2) {
@@ -16674,7 +16679,7 @@ function buildGetMessagesByConversationExpr(conversationId, limit) {
16674
16679
  }
16675
16680
  })()`;
16676
16681
  }
16677
- function buildSendMessageExpr(conversationId, message) {
16682
+ function buildSendMessageExpr(conversationId, message, dryRun = false) {
16678
16683
  const escapedConversationId = escapeForJs(conversationId);
16679
16684
  const escapedMessage = escapeForJs(message);
16680
16685
  return `(async function() {
@@ -16690,8 +16695,216 @@ function buildSendMessageExpr(conversationId, message) {
16690
16695
  }
16691
16696
  var type = conversation.get ? conversation.get('type') : null;
16692
16697
  var name = conversation.get ? (conversation.get('name') || conversation.get('id')) : '${escapedConversationId}';
16693
- await conversation.sendMessage('${escapedMessage}', null, null, [], null, null, null, null, null, null);
16694
- return { ok: true, name: name, type: type };
16698
+ function normalizeMentionName(value) {
16699
+ return String(value || '')
16700
+ .replace(/\\s+/g, ' ')
16701
+ .replace(/\\u200B/g, '')
16702
+ .trim();
16703
+ }
16704
+ function addLookup(lookup, name, id, label) {
16705
+ var normalized = normalizeMentionName(name);
16706
+ if (!normalized || !id || lookup[normalized]) return;
16707
+ lookup[normalized] = { uid: id, label: normalizeMentionName(label || name) };
16708
+ }
16709
+ function addMentionAliases(lookup, name, id) {
16710
+ var normalized = normalizeMentionName(name);
16711
+ addLookup(lookup, normalized, id, normalized);
16712
+ addLookup(lookup, normalized.replace(/\\s*\\([^)]*\\)\\s*$/g, ''), id, normalized);
16713
+ addLookup(lookup, normalized.replace(/\\s*\\[[^\\]]*\\]\\s*$/g, ''), id, normalized);
16714
+ addLookup(lookup, normalized.replace(/\\s*[\uFF08][^\uFF09]*[\uFF09]\\s*$/g, ''), id, normalized);
16715
+ }
16716
+ function addContactToLookup(lookup, contact) {
16717
+ if (!contact) return;
16718
+ var id = normalizeMentionName(contact && contact.get ? contact.get('id') : contact && contact.id);
16719
+ if (!id) return;
16720
+ addMentionAliases(lookup, contact && contact.get ? contact.get('name') : contact && contact.name, id);
16721
+ addMentionAliases(lookup, contact && contact.get ? contact.get('profileName') : contact && contact.profileName, id);
16722
+ addMentionAliases(lookup, contact && contact.get ? contact.get('title') : contact && contact.title, id);
16723
+ }
16724
+ function buildMentionLookup() {
16725
+ var lookup = {};
16726
+ var all = [];
16727
+ if (controller && typeof controller.getAllPrivateConversations === 'function') {
16728
+ var privates = controller.getAllPrivateConversations();
16729
+ all = privates.models || privates || [];
16730
+ }
16731
+ for (var i = 0; i < all.length; i++) {
16732
+ addContactToLookup(lookup, all[i]);
16733
+ }
16734
+ var memberIds = [];
16735
+ var membersV2 = conversation && conversation.get ? (conversation.get('membersV2') || []) : [];
16736
+ var members = conversation && conversation.get ? (conversation.get('members') || []) : [];
16737
+ for (var j = 0; j < membersV2.length; j++) {
16738
+ memberIds.push(membersV2[j].id || membersV2[j]);
16739
+ addMentionAliases(lookup, membersV2[j].displayName, membersV2[j].id);
16740
+ }
16741
+ for (var k = 0; k < members.length; k++) {
16742
+ memberIds.push(members[k]);
16743
+ }
16744
+ for (var m = 0; m < memberIds.length; m++) {
16745
+ var memberContact = controller.get(memberIds[m]);
16746
+ if (memberContact) addContactToLookup(lookup, memberContact);
16747
+ }
16748
+ return lookup;
16749
+ }
16750
+ function normalizeMentionKey(value) {
16751
+ return normalizeMentionName(value)
16752
+ .replace(/^@+/, '')
16753
+ .replace(/\\s*\\([^)]*\\)\\s*$/g, '')
16754
+ .replace(/\\s*\\[[^\\]]*\\]\\s*$/g, '')
16755
+ .replace(/\\s*[\uFF08][^\uFF09]*[\uFF09]\\s*$/g, '')
16756
+ .toLowerCase()
16757
+ .replace(/[^\\p{L}\\p{N}]+/gu, ' ')
16758
+ .trim();
16759
+ }
16760
+ function hasWordBoundary(text, end) {
16761
+ return end >= text.length || !/[\\p{L}\\p{N}_]/u.test(text[end]);
16762
+ }
16763
+ function readMentionQuery(text, atIndex) {
16764
+ var start = atIndex + 1;
16765
+ var end = start;
16766
+ while (end < text.length && /[\\p{L}\\p{N}_-]/u.test(text[end])) {
16767
+ end += 1;
16768
+ }
16769
+ if (end === start) return null;
16770
+ return { raw: text.slice(start, end), start: atIndex, end: end };
16771
+ }
16772
+ function resolveFuzzyMention(query, lookup) {
16773
+ var queryKey = normalizeMentionKey(query);
16774
+ if (!queryKey) return { uid: null, reason: 'empty-query', candidates: [] };
16775
+ var scoresByUid = {};
16776
+ var labelsByUid = {};
16777
+ var aliases = Object.keys(lookup);
16778
+ for (var i = 0; i < aliases.length; i++) {
16779
+ var alias = aliases[i];
16780
+ var aliasKey = normalizeMentionKey(alias);
16781
+ if (!aliasKey) continue;
16782
+ var score = 0;
16783
+ var aliasTokens = aliasKey.split(' ');
16784
+ if (aliasKey === queryKey) score = 100;
16785
+ else if (aliasTokens.indexOf(queryKey) !== -1) score = 80;
16786
+ else if (aliasKey.indexOf(queryKey) !== -1) score = 60;
16787
+ else if (queryKey.indexOf(aliasKey) !== -1) score = 40;
16788
+ if (score === 0) continue;
16789
+ var entry = lookup[alias];
16790
+ var uid = entry.uid;
16791
+ if (!scoresByUid[uid] || score > scoresByUid[uid]) {
16792
+ scoresByUid[uid] = score;
16793
+ labelsByUid[uid] = entry.label || alias;
16794
+ }
16795
+ }
16796
+ var bestUid = null;
16797
+ var bestScore = 0;
16798
+ var bestCount = 0;
16799
+ var uids = Object.keys(scoresByUid);
16800
+ var candidates = uids.map(function(uid) {
16801
+ return { uid: uid, name: labelsByUid[uid], score: scoresByUid[uid] };
16802
+ }).sort(function(a, b) { return b.score - a.score || String(a.name || '').localeCompare(String(b.name || '')); });
16803
+ for (var j = 0; j < uids.length; j++) {
16804
+ var uidScore = scoresByUid[uids[j]];
16805
+ if (uidScore > bestScore) {
16806
+ bestUid = uids[j];
16807
+ bestScore = uidScore;
16808
+ bestCount = 1;
16809
+ } else if (uidScore === bestScore) {
16810
+ bestCount += 1;
16811
+ }
16812
+ }
16813
+ if (!bestUid) return { uid: null, reason: 'no-match', candidates: candidates.slice(0, 5) };
16814
+ if (bestCount !== 1) return { uid: null, reason: 'ambiguous', candidates: candidates.slice(0, 5) };
16815
+ return { uid: bestUid, label: labelsByUid[bestUid], reason: 'matched', candidates: candidates.slice(0, 5) };
16816
+ }
16817
+ function extractMentions(text) {
16818
+ var lookup = buildMentionLookup();
16819
+ var names = Object.keys(lookup).sort(function(a, b) { return b.length - a.length; });
16820
+ var replacements = [];
16821
+ var debug = [];
16822
+ var occupied = [];
16823
+ function overlaps(start, end) {
16824
+ for (var i = 0; i < occupied.length; i++) {
16825
+ if (start < occupied[i].end && end > occupied[i].start) return true;
16826
+ }
16827
+ return false;
16828
+ }
16829
+ var atIndex = 0;
16830
+ while (atIndex < text.length) {
16831
+ var idx = text.indexOf('@', atIndex);
16832
+ if (idx === -1) break;
16833
+ if (overlaps(idx, idx + 1)) {
16834
+ atIndex = idx + 1;
16835
+ continue;
16836
+ }
16837
+ var matched = null;
16838
+ var debugItem = { raw: null, start: idx, matched: false, reason: 'not-parsed', uid: null, candidates: [] };
16839
+ for (var i = 0; i < names.length; i++) {
16840
+ var mentionText = '@' + names[i];
16841
+ if (text.slice(idx, idx + mentionText.length) === mentionText && hasWordBoundary(text, idx + mentionText.length)) {
16842
+ var entry = lookup[names[i]];
16843
+ matched = { uid: entry.uid, label: entry.label || names[i], start: idx, end: idx + mentionText.length };
16844
+ debugItem = { raw: mentionText, start: idx, matched: true, reason: 'exact', uid: matched.uid, replacement: '@' + matched.label, candidates: [{ uid: matched.uid, name: matched.label, score: 100 }] };
16845
+ break;
16846
+ }
16847
+ }
16848
+ if (!matched) {
16849
+ var query = readMentionQuery(text, idx);
16850
+ if (query) {
16851
+ var fuzzy = resolveFuzzyMention(query.raw, lookup);
16852
+ debugItem = { raw: '@' + query.raw, start: query.start, matched: !!fuzzy.uid, reason: fuzzy.reason, uid: fuzzy.uid, replacement: fuzzy.label ? '@' + fuzzy.label : null, candidates: fuzzy.candidates };
16853
+ if (fuzzy.uid) {
16854
+ matched = { uid: fuzzy.uid, label: fuzzy.label || query.raw, start: query.start, end: query.end };
16855
+ }
16856
+ }
16857
+ }
16858
+ if (matched && !overlaps(matched.start, matched.end)) {
16859
+ replacements.push({ uid: matched.uid, label: matched.label, start: matched.start, end: matched.end });
16860
+ occupied.push({ start: matched.start, end: matched.end });
16861
+ debugItem.matched = true;
16862
+ debugItem.uid = matched.uid;
16863
+ debugItem.replacement = '@' + matched.label;
16864
+ atIndex = matched.end;
16865
+ } else {
16866
+ atIndex = idx + 1;
16867
+ }
16868
+ debug.push(debugItem);
16869
+ }
16870
+ replacements.sort(function(a, b) { return a.start - b.start; });
16871
+ var finalText = '';
16872
+ var mentions = [];
16873
+ var cursor = 0;
16874
+ for (var r = 0; r < replacements.length; r++) {
16875
+ var replacement = '@' + replacements[r].label;
16876
+ finalText += text.slice(cursor, replacements[r].start);
16877
+ var finalStart = finalText.length;
16878
+ finalText += replacement;
16879
+ mentions.push({ uid: replacements[r].uid, start: finalStart, length: replacement.length, type: 0 });
16880
+ cursor = replacements[r].end;
16881
+ }
16882
+ finalText += text.slice(cursor);
16883
+ mentions.sort(function(a, b) { return a.start - b.start; });
16884
+ return { message: finalText, mentions: mentions, debug: debug, lookupSize: names.length };
16885
+ }
16886
+ var plan = extractMentions('${escapedMessage}');
16887
+ var mentions = plan.mentions;
16888
+ var mentionTarget = mentions.length > 0 ? mentions[0].uid : null;
16889
+ var mentionsArg = mentions.length > 0 ? mentions : null;
16890
+ if (${dryRun ? "true" : "false"}) {
16891
+ return {
16892
+ ok: true,
16893
+ dryRun: true,
16894
+ conversationId: '${escapedConversationId}',
16895
+ inputMessage: '${escapedMessage}',
16896
+ message: plan.message,
16897
+ name: name,
16898
+ type: type,
16899
+ mentionTarget: mentionTarget,
16900
+ mentions: mentions,
16901
+ mentionCount: mentions.length,
16902
+ mentionDebug: plan.debug,
16903
+ mentionLookupSize: plan.lookupSize
16904
+ };
16905
+ }
16906
+ await conversation.sendMessage(plan.message, mentionTarget, mentionsArg, [], null, null, null, null, null, null);
16907
+ return { ok: true, name: name, type: type, mentionCount: mentions.length };
16695
16908
  } catch(e) {
16696
16909
  return { ok: false, reason: e && e.message ? e.message : String(e) };
16697
16910
  }
@@ -25219,6 +25432,7 @@ function parseIm1ReplyArgs(tokens) {
25219
25432
  const targetTokens = [];
25220
25433
  let thread;
25221
25434
  let text;
25435
+ let dryRun = false;
25222
25436
  while (rest.length > 0) {
25223
25437
  const token = rest.shift();
25224
25438
  switch (token) {
@@ -25228,6 +25442,10 @@ function parseIm1ReplyArgs(tokens) {
25228
25442
  case "--text":
25229
25443
  text = requireValue11(rest, token);
25230
25444
  break;
25445
+ case "--dryrun":
25446
+ case "--dry-run":
25447
+ dryRun = true;
25448
+ break;
25231
25449
  case "--source":
25232
25450
  case "--endpoint":
25233
25451
  targetTokens.push(token, requireValue11(rest, token));
@@ -25249,7 +25467,8 @@ function parseIm1ReplyArgs(tokens) {
25249
25467
  source: target.source,
25250
25468
  endpoint: target.endpoint,
25251
25469
  thread,
25252
- text
25470
+ text,
25471
+ dryRun
25253
25472
  };
25254
25473
  }
25255
25474
  function parseTargetOptions(tokens) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/cli",
3
- "version": "0.24.44",
3
+ "version": "0.25.1",
4
4
  "description": "CLI utilities for the pMate project",
5
5
  "license": "MIT",
6
6
  "bin": {