@pmate/cli 0.21.15 → 0.21.17

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.js CHANGED
@@ -9435,8 +9435,8 @@ __export(index_exports, {
9435
9435
  parseCommandArgs: () => parseCommandArgs
9436
9436
  });
9437
9437
  module.exports = __toCommonJS(index_exports);
9438
- var import_node_fs21 = require("fs");
9439
- var import_node_path26 = __toESM(require("path"));
9438
+ var import_node_fs22 = require("fs");
9439
+ var import_node_path27 = __toESM(require("path"));
9440
9440
  var import_chalk4 = __toESM(require("chalk"));
9441
9441
 
9442
9442
  // src/cli.ts
@@ -14585,9 +14585,9 @@ ${indent}\`\`\``;
14585
14585
  static richTextToPlain(richText) {
14586
14586
  return richText.map((item) => item.plain_text ?? item.text?.content ?? "").join("").trim();
14587
14587
  }
14588
- static async requestJson(path27, init) {
14588
+ static async requestJson(path28, init) {
14589
14589
  const token = this.getToken();
14590
- const response = await fetch(`${this.baseUrl}${path27}`, {
14590
+ const response = await fetch(`${this.baseUrl}${path28}`, {
14591
14591
  method: init.method,
14592
14592
  headers: {
14593
14593
  Authorization: `Bearer ${token}`,
@@ -15664,6 +15664,10 @@ var QuizCommandHandler = class {
15664
15664
 
15665
15665
  // src/commands/CollectCommandHandler.ts
15666
15666
  var import_playwright = require("playwright");
15667
+ var import_node_crypto4 = require("crypto");
15668
+ var import_node_fs12 = require("fs");
15669
+ var import_node_os7 = __toESM(require("os"));
15670
+ var import_node_path17 = __toESM(require("path"));
15667
15671
 
15668
15672
  // src/collectStore.ts
15669
15673
  var import_node_crypto3 = require("crypto");
@@ -15683,30 +15687,18 @@ function toThreadKey(name) {
15683
15687
  return `${base}-${suffix}`;
15684
15688
  }
15685
15689
  async function readStoredThread(rootDir, threadKey) {
15686
- const filePath = getThreadMetaFilePath(rootDir, threadKey);
15690
+ const filePath = getThreadFilePath(rootDir, threadKey);
15687
15691
  try {
15688
15692
  const raw = await import_node_fs11.promises.readFile(filePath, "utf8");
15689
- const parsed = JSON.parse(raw);
15690
- if ("messages" in parsed && Array.isArray(parsed.messages)) {
15691
- return parsed;
15692
- }
15693
- const messages2 = await readStoredMessages(rootDir, threadKey);
15694
- return {
15695
- ...parsed,
15696
- messages: messages2
15697
- };
15693
+ return JSON.parse(raw);
15698
15694
  } catch {
15699
- return readLegacyStoredThread(rootDir, threadKey);
15695
+ return null;
15700
15696
  }
15701
15697
  }
15702
15698
  async function writeStoredThread(rootDir, thread) {
15703
- const metaPath = getThreadMetaFilePath(rootDir, thread.threadKey);
15704
- const messagePath = getThreadMessagesFilePath(rootDir, thread.threadKey);
15705
- const { messages: messages2, ...meta } = thread;
15706
- await import_node_fs11.promises.mkdir(import_node_path16.default.dirname(metaPath), { recursive: true });
15707
- await import_node_fs11.promises.writeFile(metaPath, JSON.stringify(meta, null, 2) + "\n", "utf8");
15708
- const body = messages2.map((message) => JSON.stringify(message)).join("\n");
15709
- await import_node_fs11.promises.writeFile(messagePath, `${body}${body ? "\n" : ""}`, "utf8");
15699
+ const filePath = getThreadFilePath(rootDir, thread.threadKey);
15700
+ await import_node_fs11.promises.mkdir(import_node_path16.default.dirname(filePath), { recursive: true });
15701
+ await import_node_fs11.promises.writeFile(filePath, JSON.stringify(thread, null, 2) + "\n", "utf8");
15710
15702
  }
15711
15703
  async function writeStoredIndex(rootDir, index) {
15712
15704
  await import_node_fs11.promises.mkdir(rootDir, { recursive: true });
@@ -15714,91 +15706,22 @@ async function writeStoredIndex(rootDir, index) {
15714
15706
  await import_node_fs11.promises.writeFile(filePath, JSON.stringify(index, null, 2) + "\n", "utf8");
15715
15707
  }
15716
15708
  function mergeMessages(existing, incoming) {
15717
- const seenMessageIds = new Set(
15718
- existing.map((message) => normalizeMessageId(message.messageId)).filter((value) => !!value)
15719
- );
15709
+ const seen = new Set(existing.map((message) => message.hash));
15720
15710
  const merged = [...existing];
15721
15711
  let added = 0;
15722
15712
  for (const message of incoming) {
15723
- const incomingMessageId = normalizeMessageId(message.messageId);
15724
- if (incomingMessageId && seenMessageIds.has(incomingMessageId)) {
15725
- continue;
15726
- }
15727
- const upgradeIndex = merged.findIndex((current) => shouldUpgradeMessage(current, message));
15728
- if (upgradeIndex >= 0) {
15729
- merged[upgradeIndex] = message;
15730
- if (incomingMessageId) {
15731
- seenMessageIds.add(incomingMessageId);
15732
- }
15713
+ if (seen.has(message.hash)) {
15733
15714
  continue;
15734
15715
  }
15735
- if (incomingMessageId) {
15736
- seenMessageIds.add(incomingMessageId);
15737
- }
15716
+ seen.add(message.hash);
15738
15717
  merged.push(message);
15739
15718
  added += 1;
15740
15719
  }
15741
15720
  return { messages: merged, added };
15742
15721
  }
15743
- function shouldUpgradeMessage(existing, incoming) {
15744
- const existingMessageId = normalizeMessageId(existing.messageId);
15745
- const incomingMessageId = normalizeMessageId(incoming.messageId);
15746
- if (existingMessageId && incomingMessageId && existingMessageId === incomingMessageId) {
15747
- return false;
15748
- }
15749
- if (existing.time && incoming.time && existing.time !== incoming.time) {
15750
- return false;
15751
- }
15752
- return normalizeMessageField(existing.sender) === normalizeMessageField(incoming.sender) && normalizeMessageField(existing.content) === normalizeMessageField(incoming.content) && joinNormalized(existing.links) === joinNormalized(incoming.links) && joinNormalized(existing.images) === joinNormalized(incoming.images) && (!!incoming.time && !existing.time);
15753
- }
15754
- function normalizeMessageField(value) {
15755
- return (value ?? "").trim();
15756
- }
15757
- function normalizeMessageId(value) {
15758
- const normalized = (value ?? "").trim();
15759
- return normalized || null;
15760
- }
15761
- function joinNormalized(values) {
15762
- return values.map((value) => value.trim()).join("|");
15763
- }
15764
- async function readStoredMessages(rootDir, threadKey) {
15765
- const filePath = getThreadMessagesFilePath(rootDir, threadKey);
15766
- try {
15767
- const raw = await import_node_fs11.promises.readFile(filePath, "utf8");
15768
- return raw.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => normalizeStoredMessage(JSON.parse(line)));
15769
- } catch {
15770
- return [];
15771
- }
15772
- }
15773
- async function readLegacyStoredThread(rootDir, threadKey) {
15774
- const filePath = getLegacyThreadFilePath(rootDir, threadKey);
15775
- try {
15776
- const raw = await import_node_fs11.promises.readFile(filePath, "utf8");
15777
- return JSON.parse(raw);
15778
- } catch {
15779
- return null;
15780
- }
15781
- }
15782
- function getThreadMetaFilePath(rootDir, threadKey) {
15783
- return import_node_path16.default.join(rootDir, "threads", `${threadKey}.json`);
15784
- }
15785
- function getThreadMessagesFilePath(rootDir, threadKey) {
15786
- return import_node_path16.default.join(rootDir, "threads", `${threadKey}.jsonl`);
15787
- }
15788
- function getLegacyThreadFilePath(rootDir, threadKey) {
15722
+ function getThreadFilePath(rootDir, threadKey) {
15789
15723
  return import_node_path16.default.join(rootDir, "threads", `${threadKey}.json`);
15790
15724
  }
15791
- function normalizeStoredMessage(message) {
15792
- return {
15793
- messageId: normalizeMessageId(message.messageId),
15794
- time: message.time ?? null,
15795
- sender: message.sender ?? null,
15796
- content: message.content ?? "",
15797
- links: Array.isArray(message.links) ? message.links : [],
15798
- images: Array.isArray(message.images) ? message.images : [],
15799
- collectedAt: message.collectedAt
15800
- };
15801
- }
15802
15725
 
15803
15726
  // src/commands/CollectCommandHandler.ts
15804
15727
  var CollectCommandHandler = class {
@@ -15813,39 +15736,22 @@ var CollectCommandHandler = class {
15813
15736
  if (!targetPage) {
15814
15737
  throw new Error("Cannot find target page from CDP contexts.");
15815
15738
  }
15816
- const threads = await this.extractThreadsFromConversationData(targetPage);
15739
+ const { rows } = await this.locateThreadRows(targetPage);
15740
+ const threads = await this.extractThreads(rows);
15817
15741
  if (threads.length === 0) {
15818
- throw new Error("No threads found in CC data store.");
15742
+ throw new Error("No threads found in target page.");
15819
15743
  }
15820
15744
  const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
15821
15745
  const results = [];
15822
- const failures = [];
15823
15746
  for (const thread of threads) {
15824
- try {
15825
- const threadKey = toThreadKey(thread.name);
15826
- const existing = await readStoredThread(target.rootDir, threadKey);
15827
- const messages2 = await this.extractMessages(targetPage, thread, existing?.messages ?? []);
15828
- const result = await this.persistThread(
15829
- target.rootDir,
15830
- target,
15831
- thread,
15832
- messages2,
15833
- syncedAt,
15834
- existing
15835
- );
15836
- results.push(result);
15837
- } catch (error) {
15838
- const message = error instanceof Error ? error.message : String(error);
15839
- failures.push({ threadName: thread.name, message });
15840
- ui.warn(`Skipped thread: ${thread.name}`, message);
15841
- }
15842
- }
15843
- if (results.length === 0) {
15844
- const firstFailure = failures[0]?.message ?? "No thread could be collected.";
15845
- throw new Error(firstFailure);
15747
+ await this.clickThreadRow(rows, thread);
15748
+ await targetPage.waitForTimeout(1200);
15749
+ const messages2 = await this.extractMessages(targetPage, thread.name);
15750
+ const result = await this.persistThread(target.rootDir, target, thread, messages2, syncedAt);
15751
+ results.push(result);
15846
15752
  }
15847
15753
  await this.writeIndex(target.rootDir, target, results, syncedAt);
15848
- this.printSyncSummary(target.sourceKey, target.rootDir, threads.length, results, failures);
15754
+ this.printSyncSummary(target.sourceKey, target.rootDir, threads.length, results);
15849
15755
  } catch (error) {
15850
15756
  const message = error instanceof Error ? error.message : String(error);
15851
15757
  throw new Error(`collect failed: ${message}`);
@@ -15853,10 +15759,11 @@ var CollectCommandHandler = class {
15853
15759
  await browser?.close().catch(() => void 0);
15854
15760
  }
15855
15761
  }
15856
- async persistThread(rootDir, target, thread, messages2, syncedAt, existing) {
15762
+ async persistThread(rootDir, target, thread, messages2, syncedAt) {
15857
15763
  const threadKey = toThreadKey(thread.name);
15764
+ const existing = await readStoredThread(rootDir, threadKey);
15858
15765
  const incoming = messages2.map((message) => ({
15859
- messageId: message.messageId,
15766
+ hash: message.hash,
15860
15767
  time: message.time,
15861
15768
  sender: message.sender,
15862
15769
  content: message.content,
@@ -15904,18 +15811,14 @@ var CollectCommandHandler = class {
15904
15811
  threads
15905
15812
  });
15906
15813
  }
15907
- printSyncSummary(sourceKey, rootDir, scannedThreads, results, failures) {
15814
+ printSyncSummary(sourceKey, rootDir, scannedThreads, results) {
15908
15815
  const updatedThreads = results.filter((result) => result.updated).length;
15909
15816
  const newMessages = results.reduce((sum, result) => sum + result.addedMessages, 0);
15910
15817
  ui.plain(`Synced source: ${sourceKey}`);
15911
15818
  ui.plain(`Threads scanned: ${scannedThreads}`);
15912
15819
  ui.plain(`Threads updated: ${updatedThreads}`);
15913
- ui.plain(`Threads failed: ${failures.length}`);
15914
15820
  ui.plain(`New messages: ${newMessages}`);
15915
15821
  ui.plain(`Saved under: ${rootDir}`);
15916
- for (const failure of failures.slice(0, 10)) {
15917
- ui.warn(`Thread failed: ${failure.threadName}`, failure.message);
15918
- }
15919
15822
  }
15920
15823
  async pickTargetPage(pages) {
15921
15824
  let best = null;
@@ -15930,307 +15833,364 @@ var CollectCommandHandler = class {
15930
15833
  }
15931
15834
  return best?.page ?? null;
15932
15835
  }
15933
- async extractThreadsFromConversationData(page) {
15934
- const result = await this.evaluateInPage(page, buildListThreadsExpr()).catch((error) => ({
15935
- ok: false,
15936
- reason: error instanceof Error ? error.message : String(error)
15937
- }));
15938
- if (!result || !("ok" in result) || !result.ok || !Array.isArray(result.threads)) {
15939
- throw new Error(
15940
- result && "reason" in result && typeof result.reason === "string" ? result.reason : "unknown error"
15941
- );
15836
+ async locateThreadRows(page) {
15837
+ const preferred = page.locator(".ReactVirtualized__Grid__innerScrollContainer").first();
15838
+ const preferredCount = await preferred.locator(":scope > *").count().catch(() => 0);
15839
+ if (preferredCount >= 1) {
15840
+ return { rows: preferred.locator(":scope > *") };
15841
+ }
15842
+ const seeds = [
15843
+ '[role="list"]',
15844
+ '[role="listbox"]',
15845
+ '[class*="list" i]',
15846
+ '[class*="conversation" i]',
15847
+ '[class*="thread" i]',
15848
+ '[class*="chat" i]',
15849
+ "div"
15850
+ ];
15851
+ let best = null;
15852
+ for (const seed of seeds) {
15853
+ const containers = page.locator(seed);
15854
+ const count = await containers.count().catch(() => 0);
15855
+ const max = seed === "div" ? Math.min(count, 180) : Math.min(count, 40);
15856
+ for (let i = 0; i < max; i += 1) {
15857
+ const rows = containers.nth(i).locator(":scope > *");
15858
+ const rowCount = await rows.count().catch(() => 0);
15859
+ if (rowCount < 1 || rowCount > 500) {
15860
+ continue;
15861
+ }
15862
+ const textCount = await containers.nth(i).locator("text=/./").count().catch(() => 0);
15863
+ const score = rowCount + Math.min(textCount, rowCount * 4);
15864
+ if (!best || score > best.score) {
15865
+ best = { rows, score };
15866
+ }
15867
+ }
15942
15868
  }
15943
- return result.threads.map((thread) => ({
15944
- conversationId: normalizeText(thread.conversationId ?? ""),
15945
- name: normalizeText(thread.name ?? ""),
15946
- unread: normalizeUnreadCount(thread.unread),
15947
- preview: normalizeText(thread.preview ?? ""),
15948
- time: formatSentAt(thread.sentAt)
15949
- })).filter((thread) => thread.conversationId && thread.name);
15950
- }
15951
- async extractMessages(page, thread, existingMessages) {
15952
- const fromDataStore = await this.extractMessagesFromConversationData(
15953
- page,
15954
- thread,
15955
- existingMessages
15956
- );
15957
- if ("error" in fromDataStore) {
15958
- throw new Error(
15959
- `Failed to load messages from CC data store for thread: ${thread.name} (${fromDataStore.error})`
15960
- );
15869
+ if (!best) {
15870
+ throw new Error("Failed to detect thread list container.");
15961
15871
  }
15962
- return fromDataStore.messages;
15872
+ return { rows: best.rows };
15963
15873
  }
15964
- async extractMessagesFromConversationData(page, thread, existingMessages) {
15965
- const limit = Math.max(existingMessages.length + 40, 100);
15966
- const result = await this.evaluateInPage(
15967
- page,
15968
- buildGetMessagesByConversationExpr(thread.conversationId, limit)
15969
- ).catch((error) => ({ ok: false, reason: error instanceof Error ? error.message : String(error) }));
15970
- if (!result || !("ok" in result) || !result.ok || !Array.isArray(result.messages)) {
15971
- return {
15972
- error: result && "reason" in result && typeof result.reason === "string" ? result.reason : "unknown error"
15973
- };
15974
- }
15975
- const seenMessageIds = new Set(
15976
- existingMessages.map((message) => (message.messageId ?? "").trim()).filter((value) => !!value)
15977
- );
15978
- const collected = [];
15979
- for (let i = result.messages.length - 1; i >= 0; i -= 1) {
15980
- const raw = result.messages[i];
15981
- const contentParts = [normalizeText(raw.body ?? "")];
15982
- if (raw.quote?.text) {
15983
- contentParts.unshift(`Quote: ${normalizeText(raw.quote.text)}`);
15984
- }
15985
- const attachmentPaths = Array.isArray(raw.attachments) ? raw.attachments.map((attachment) => attachment.path ?? null).filter((value) => !!value) : [];
15874
+ async extractThreads(rows) {
15875
+ const count = await rows.count().catch(() => 0);
15876
+ const result = [];
15877
+ for (let i = 0; i < count; i += 1) {
15878
+ const lines = await this.collectLines(rows.nth(i), 12);
15879
+ if (lines.length === 0) {
15880
+ continue;
15881
+ }
15882
+ const unread = this.extractUnread(lines);
15883
+ const time = this.findTime(lines);
15884
+ const name = this.findThreadName(lines, time);
15885
+ if (!name) {
15886
+ continue;
15887
+ }
15888
+ const preview = lines.find(
15889
+ (line) => line !== name && line !== time && !/^\d{1,4}\+?$/.test(line) && !/^\[[^\]]+\]$/.test(line)
15890
+ ) ?? "";
15891
+ result.push({ index: i, name, unread, preview, time });
15892
+ }
15893
+ return dedupeThreads(result);
15894
+ }
15895
+ async extractMessages(page, threadName) {
15896
+ const container = await this.locateMessageContainer(page);
15897
+ const rows = container.locator(":scope > *");
15898
+ const count = await rows.count().catch(() => 0);
15899
+ const messages2 = [];
15900
+ let lastFingerprint = "";
15901
+ for (let i = 0; i < count; i += 1) {
15902
+ const row = rows.nth(i);
15903
+ const rawText = normalizeText(await row.textContent().catch(() => "") || "");
15904
+ const links = await this.extractLinks(row);
15905
+ const images = await this.extractImages(row);
15906
+ const parsed = parseMessageText(rawText);
15986
15907
  const message = {
15987
- index: raw.index,
15988
- messageId: normalizeText(raw.id ?? "") || null,
15989
- time: formatSentAt(raw.sentAt),
15990
- sender: normalizeText(raw.senderName ?? raw.source ?? "") || null,
15991
- content: contentParts.filter(Boolean).join("\n") || (attachmentPaths.length > 0 ? "[Image]" : ""),
15992
- links: [],
15993
- images: attachmentPaths
15908
+ index: i,
15909
+ hash: "",
15910
+ time: parsed.time,
15911
+ sender: parsed.sender,
15912
+ content: parsed.content || (images.length > 0 ? "[Image]" : ""),
15913
+ links,
15914
+ images
15994
15915
  };
15995
- if (!message.content && message.images.length === 0) {
15916
+ message.hash = computeMessageHash(threadName, message);
15917
+ const fingerprint = [
15918
+ message.time ?? "",
15919
+ message.sender ?? "",
15920
+ message.content,
15921
+ message.links.join("|"),
15922
+ message.images.join("|")
15923
+ ].join("||");
15924
+ if (!message.content && message.links.length === 0 && message.images.length === 0) {
15996
15925
  continue;
15997
15926
  }
15998
- if (message.messageId && seenMessageIds.has(message.messageId)) {
15999
- break;
15927
+ if (fingerprint === lastFingerprint) {
15928
+ continue;
16000
15929
  }
16001
- collected.push(message);
15930
+ lastFingerprint = fingerprint;
15931
+ messages2.push(message);
16002
15932
  }
16003
- return { messages: finalizeIncrementalMessages(collected, true) };
15933
+ return messages2;
16004
15934
  }
16005
- async evaluateInPage(page, expression) {
16006
- const session = await page.context().newCDPSession(page);
16007
- try {
16008
- const response = await session.send("Runtime.evaluate", {
16009
- expression,
16010
- returnByValue: true,
16011
- awaitPromise: true
16012
- });
16013
- if (response.exceptionDetails) {
16014
- throw new Error(response.exceptionDetails.text || "Runtime.evaluate failed");
15935
+ async clickThreadRow(rows, matched) {
15936
+ const row = rows.nth(matched.index);
15937
+ const clicked = await this.tryClick(row);
15938
+ if (!clicked) {
15939
+ const exactInRows = rows.filter({ hasText: matched.name }).first();
15940
+ const exactCount = await exactInRows.count().catch(() => 0);
15941
+ if (exactCount > 0 && await this.tryClick(exactInRows)) {
15942
+ return;
16015
15943
  }
16016
- return response.result?.value;
16017
- } finally {
16018
- await session.detach().catch(() => void 0);
15944
+ throw new Error(`Failed to select thread row: ${matched.name}`);
16019
15945
  }
16020
15946
  }
16021
- };
16022
- function normalizeText(value) {
16023
- return value.replace(/\s+/g, " ").replace(/\u200B/g, "").trim();
16024
- }
16025
- function normalizeUnreadCount(value) {
16026
- const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number.parseInt(value, 10) : 0;
16027
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
16028
- }
16029
- function buildListThreadsExpr() {
16030
- return `(function() {
15947
+ async tryClick(row) {
16031
15948
  try {
16032
- var runtime = globalThis;
16033
- var controller = runtime.ConversationController;
16034
- if (!controller) return { ok: false, reason: 'ConversationController unavailable' };
16035
- function normalize(value) {
16036
- return String(value || '').replace(/\\s+/g, ' ').trim();
16037
- }
16038
- function pickName(model) {
16039
- var fields = [
16040
- model && model.get ? model.get('name') : model && model.name,
16041
- model && model.get ? model.get('groupDisplayName') : model && model.groupDisplayName,
16042
- model && model.get ? model.get('title') : model && model.title,
16043
- model && model.get ? model.get('profileName') : model && model.profileName,
16044
- model && model.get ? model.get('e164') : model && model.e164,
16045
- model && model.get ? model.get('id') : model && model.id,
16046
- ];
16047
- for (var i = 0; i < fields.length; i++) {
16048
- var value = normalize(fields[i]);
16049
- if (value) return value;
16050
- }
16051
- return '';
16052
- }
16053
- function pickPreview(model) {
16054
- var attrs = typeof model.attributes === 'object' ? model.attributes : model || {};
16055
- var fields = [
16056
- attrs.draft,
16057
- attrs.lastMessage,
16058
- attrs.lastMessageText,
16059
- attrs.snippet,
16060
- attrs.body,
16061
- ];
16062
- for (var i = 0; i < fields.length; i++) {
16063
- var value = normalize(fields[i]);
16064
- if (value) return value;
16065
- }
16066
- return '';
16067
- }
16068
- function pickUnread(model) {
16069
- var attrs = typeof model.attributes === 'object' ? model.attributes : model || {};
16070
- var candidates = [
16071
- attrs.unreadCount,
16072
- attrs.unreadMessagesCount,
16073
- attrs.unread,
16074
- model && model.get ? model.get('unreadCount') : null,
16075
- model && model.get ? model.get('unreadMessagesCount') : null,
16076
- model && model.get ? model.get('unread') : null,
16077
- ];
16078
- for (var i = 0; i < candidates.length; i++) {
16079
- var value = Number(candidates[i] || 0);
16080
- if (Number.isFinite(value) && value > 0) return value;
16081
- }
16082
- return 0;
15949
+ await row.scrollIntoViewIfNeeded({ timeout: 3e3 });
15950
+ await row.click({ timeout: 5e3 });
15951
+ return true;
15952
+ } catch {
15953
+ return false;
15954
+ }
15955
+ }
15956
+ async extractLinks(row) {
15957
+ const links = row.locator("a[href]");
15958
+ const count = await links.count().catch(() => 0);
15959
+ const out = [];
15960
+ for (let i = 0; i < count; i += 1) {
15961
+ const href = await links.nth(i).getAttribute("href").catch(() => null);
15962
+ if (href && !out.includes(href)) {
15963
+ out.push(href);
16083
15964
  }
16084
- function pickSentAt(model) {
16085
- var attrs = typeof model.attributes === 'object' ? model.attributes : model || {};
16086
- var candidates = [
16087
- attrs.active_at,
16088
- attrs.timestamp,
16089
- attrs.sent_at,
16090
- attrs.lastMessageReceivedAt,
16091
- model && model.get ? model.get('active_at') : null,
16092
- model && model.get ? model.get('timestamp') : null,
16093
- model && model.get ? model.get('sent_at') : null,
16094
- ];
16095
- for (var i = 0; i < candidates.length; i++) {
16096
- var value = Number(candidates[i] || 0);
16097
- if (Number.isFinite(value) && value > 0) return value;
15965
+ }
15966
+ return out;
15967
+ }
15968
+ async extractImages(row) {
15969
+ const imgs = row.locator(
15970
+ 'img.module-image__image, img[alt="Image attached to message"]'
15971
+ );
15972
+ const count = await imgs.count().catch(() => 0);
15973
+ const out = [];
15974
+ for (let i = 0; i < count; i += 1) {
15975
+ const src = await imgs.nth(i).getAttribute("src").catch(() => null);
15976
+ if (src && !out.includes(src)) {
15977
+ const displayable = await toDisplayableImagePath(src);
15978
+ out.push(displayable);
15979
+ }
15980
+ }
15981
+ return out;
15982
+ }
15983
+ async locateMessageContainer(page) {
15984
+ const strong = page.locator(".messages");
15985
+ const strongCount = await strong.count().catch(() => 0);
15986
+ if (strongCount > 0) {
15987
+ let bestIdx = 0;
15988
+ let bestRows = -1;
15989
+ for (let i = 0; i < strongCount; i += 1) {
15990
+ const el = strong.nth(i);
15991
+ const visible = await el.isVisible().catch(() => false);
15992
+ if (!visible) {
15993
+ continue;
15994
+ }
15995
+ const rows = await el.locator(":scope > *").count().catch(() => 0);
15996
+ if (rows >= bestRows) {
15997
+ bestRows = rows;
15998
+ bestIdx = i;
16098
15999
  }
16099
- return null;
16100
16000
  }
16101
- var all = [];
16102
- if (typeof controller.getAllPrivateConversations === 'function') {
16103
- var privates = controller.getAllPrivateConversations();
16104
- all.push.apply(all, privates.models || privates || []);
16105
- }
16106
- if (typeof controller.getAllGroups === 'function') {
16107
- var groups = controller.getAllGroups();
16108
- all.push.apply(all, groups.models || groups || []);
16109
- }
16110
- var seen = {};
16111
- var threads = [];
16112
- for (var i = 0; i < all.length; i++) {
16113
- var model = all[i];
16114
- var conversationId = normalize(model && model.get ? model.get('id') : model && model.id);
16115
- if (!conversationId || seen[conversationId]) continue;
16116
- seen[conversationId] = true;
16117
- var name = pickName(model);
16118
- if (!name) continue;
16119
- threads.push({
16120
- conversationId: conversationId,
16121
- name: name,
16122
- unread: pickUnread(model),
16123
- preview: pickPreview(model),
16124
- sentAt: pickSentAt(model),
16125
- });
16001
+ if (bestRows >= 0) {
16002
+ return strong.nth(bestIdx);
16126
16003
  }
16127
- threads.sort(function(left, right) {
16128
- return (Number(right.sentAt || 0) - Number(left.sentAt || 0)) || left.name.localeCompare(right.name);
16129
- });
16130
- return { ok: true, threads: threads };
16131
- } catch(e) {
16132
- return { ok: false, reason: e && e.message ? e.message : String(e) };
16133
16004
  }
16134
- })()`;
16135
- }
16136
- function buildGetMessagesByConversationExpr(conversationId, limit) {
16137
- const escapedConversationId = escapeForJs(conversationId);
16138
- return `(async function() {
16139
- try {
16140
- var runtime = globalThis;
16141
- var controller = runtime.ConversationController;
16142
- var signal = (runtime.window && runtime.window.Signal) || runtime.Signal;
16143
- var whisper = runtime.Whisper;
16144
- if (!controller) return { ok: false, reason: 'ConversationController unavailable' };
16145
- if (!signal || !signal.Data || !signal.Data.getMessagesByConversation || !whisper || !whisper.MessageCollection) {
16146
- return { ok: false, reason: 'Signal data APIs are unavailable' };
16147
- }
16148
- function normalize(value) {
16149
- return String(value || '').replace(/\\s+/g, ' ').trim();
16150
- }
16151
- function resolveSenderName(source, model) {
16152
- if (!source) return null;
16153
- var contact = typeof controller.get === 'function' ? controller.get(source) : null;
16154
- var fields = [
16155
- contact && contact.get ? contact.get('name') : contact && contact.name,
16156
- contact && contact.get ? contact.get('profileName') : contact && contact.profileName,
16157
- contact && contact.get ? contact.get('title') : contact && contact.title,
16158
- source,
16159
- ];
16160
- for (var i = 0; i < fields.length; i++) {
16161
- var value = normalize(fields[i]);
16162
- if (value) return value;
16163
- }
16164
- return null;
16005
+ const fallback = page.locator(".discussion-container, .conversation-stack, .main.panel, div");
16006
+ const count = await fallback.count().catch(() => 0);
16007
+ let best = null;
16008
+ for (let i = 0; i < Math.min(count, 280); i += 1) {
16009
+ const el = fallback.nth(i);
16010
+ const visible = await el.isVisible().catch(() => false);
16011
+ if (!visible) {
16012
+ continue;
16013
+ }
16014
+ const children = await el.locator(":scope > *").count().catch(() => 0);
16015
+ const texts = await el.locator("text=/./").count().catch(() => 0);
16016
+ const score = texts + children;
16017
+ if (!best || score > best.score) {
16018
+ best = { idx: i, score };
16165
16019
  }
16166
- var conversation = typeof controller.get === 'function' ? controller.get('${escapedConversationId}') : null;
16167
- if (!conversation) return { ok: false, reason: 'Conversation not found: ${escapedConversationId}' };
16168
- var fetched = await signal.Data.getMessagesByConversation('${escapedConversationId}', {
16169
- limit: ${limit},
16170
- MessageCollection: whisper.MessageCollection,
16171
- });
16172
- var models = (fetched.models || fetched || []).slice();
16173
- models.sort(function(left, right) {
16174
- var leftSentAt = left && left.get ? (left.get('sent_at') || 0) : (left && left.sent_at) || 0;
16175
- var rightSentAt = right && right.get ? (right.get('sent_at') || 0) : (right && right.sent_at) || 0;
16176
- return leftSentAt - rightSentAt;
16177
- });
16178
- return {
16179
- ok: true,
16180
- conversationId: '${escapedConversationId}',
16181
- messages: models.map(function(model, index) {
16182
- var attrs = typeof model.attributes === 'object' ? model.attributes : model;
16183
- var source = (typeof model.getSource === 'function' ? model.getSource() : attrs.source) || null;
16184
- var quote = attrs.quote ? {
16185
- id: attrs.quote.id || null,
16186
- author: attrs.quote.author || null,
16187
- text: attrs.quote.text || null,
16188
- } : null;
16189
- var attachments = Array.isArray(attrs.attachments) ? attrs.attachments.map(function(attachment) {
16190
- return {
16191
- path: attachment && attachment.path || null,
16192
- contentType: attachment && attachment.contentType || null,
16193
- fileName: attachment && attachment.fileName || null,
16194
- };
16195
- }) : [];
16196
- return {
16197
- index: index,
16198
- body: attrs.body || '',
16199
- source: source,
16200
- senderName: resolveSenderName(source, model),
16201
- sentAt: attrs.sent_at || attrs.timestamp || null,
16202
- id: attrs.id || model.id || '',
16203
- attachments: attachments,
16204
- quote: quote,
16205
- };
16206
- }),
16207
- };
16208
- } catch(e) {
16209
- return { ok: false, reason: e && e.message ? e.message : String(e) };
16210
16020
  }
16211
- })()`;
16021
+ if (!best) {
16022
+ throw new Error("Cannot find conversation container.");
16023
+ }
16024
+ return fallback.nth(best.idx);
16025
+ }
16026
+ async collectLines(row, max = 12) {
16027
+ const items = row.locator("text=/./");
16028
+ const count = await items.count().catch(() => 0);
16029
+ const lines = [];
16030
+ for (let i = 0; i < Math.min(count, max); i += 1) {
16031
+ const text = normalizeText(await items.nth(i).textContent().catch(() => "") || "");
16032
+ if (text && !lines.includes(text)) {
16033
+ lines.push(text);
16034
+ }
16035
+ }
16036
+ return lines;
16037
+ }
16038
+ extractUnread(lines) {
16039
+ let unread = 0;
16040
+ for (const line of lines) {
16041
+ if (!/^\d{1,4}\+?$/.test(line)) {
16042
+ continue;
16043
+ }
16044
+ const value = Number.parseInt(line.replace("+", ""), 10);
16045
+ if (Number.isFinite(value)) {
16046
+ unread = Math.max(unread, value);
16047
+ }
16048
+ }
16049
+ return unread;
16050
+ }
16051
+ findTime(lines) {
16052
+ return lines.find(
16053
+ (line) => /^\d{1,2}:\d{2}\s?(?:AM|PM)?$/i.test(line) || /^\d{1,2}\/\d{1,2}$/.test(line) || /^\d{4}\/\d{1,2}\/\d{1,2}$/.test(line)
16054
+ ) ?? null;
16055
+ }
16056
+ findThreadName(lines, time) {
16057
+ const candidates = [];
16058
+ for (const line of lines) {
16059
+ if (line === time) {
16060
+ continue;
16061
+ }
16062
+ if (/^\d{1,4}\+?$/.test(line)) {
16063
+ continue;
16064
+ }
16065
+ if (/^\[[^\]]+\]$/.test(line)) {
16066
+ continue;
16067
+ }
16068
+ candidates.push(line);
16069
+ }
16070
+ const alphaNoColon = candidates.find(
16071
+ (line) => /[A-Za-z\u4e00-\u9fff]/.test(line) && !line.includes(":")
16072
+ );
16073
+ if (alphaNoColon) {
16074
+ return alphaNoColon;
16075
+ }
16076
+ const alphaPreferred = candidates.find((line) => /[A-Za-z\u4e00-\u9fff]/.test(line));
16077
+ if (alphaPreferred) {
16078
+ return alphaPreferred;
16079
+ }
16080
+ return candidates[0] ?? "";
16081
+ }
16082
+ };
16083
+ function dedupeThreads(threads) {
16084
+ const seen = /* @__PURE__ */ new Set();
16085
+ const result = [];
16086
+ for (const thread of threads) {
16087
+ const key = `${thread.name}::${thread.preview}::${thread.time ?? ""}`;
16088
+ if (seen.has(key)) {
16089
+ continue;
16090
+ }
16091
+ seen.add(key);
16092
+ result.push(thread);
16093
+ }
16094
+ return result;
16212
16095
  }
16213
- function escapeForJs(value) {
16214
- return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
16096
+ function normalizeText(value) {
16097
+ return value.replace(/\s+/g, " ").replace(/\u200B/g, "").trim();
16215
16098
  }
16216
- function formatSentAt(sentAt) {
16217
- const value = typeof sentAt === "number" ? sentAt : typeof sentAt === "string" && /^\d+$/.test(sentAt) ? Number.parseInt(sentAt, 10) : NaN;
16218
- if (!Number.isFinite(value) || value <= 0) {
16219
- return null;
16099
+ function computeMessageHash(threadName, message) {
16100
+ const base = [
16101
+ normalizeText(threadName),
16102
+ normalizeText(message.sender ?? ""),
16103
+ normalizeText(message.time ?? ""),
16104
+ normalizeText(message.content),
16105
+ message.links.map(normalizeText).join("|"),
16106
+ message.images.map(normalizeText).join("|")
16107
+ ].join("||");
16108
+ return (0, import_node_crypto4.createHash)("sha1").update(base).digest("hex").slice(0, 16);
16109
+ }
16110
+ function parseMessageText(rawText) {
16111
+ const text = normalizeText(rawText);
16112
+ if (!text) {
16113
+ return { time: null, sender: null, content: "" };
16114
+ }
16115
+ const timeMatch = text.match(/^(\d{1,2}:\d{2}\s?(?:AM|PM)?)\s+(.*)$/i) ?? text.match(/^(\d{1,2}\/\d{1,2}|\d{4}\/\d{1,2}\/\d{1,2})\s+(.*)$/);
16116
+ if (!timeMatch) {
16117
+ return { time: null, sender: null, content: text };
16118
+ }
16119
+ const time = timeMatch[1];
16120
+ const rest = normalizeText(timeMatch[2] ?? "");
16121
+ if (!rest) {
16122
+ return { time, sender: null, content: "" };
16123
+ }
16124
+ const senderMatch = rest.match(/^([^:]{1,80}):\s*(.*)$/);
16125
+ if (!senderMatch) {
16126
+ return { time, sender: null, content: rest };
16220
16127
  }
16221
- const date = new Date(value);
16222
- return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
16128
+ return {
16129
+ time,
16130
+ sender: normalizeText(senderMatch[1] ?? "") || null,
16131
+ content: normalizeText(senderMatch[2] ?? "")
16132
+ };
16223
16133
  }
16224
- function finalizeIncrementalMessages(collectedNewestFirst, _reachedKnownMessage) {
16225
- return [...collectedNewestFirst].reverse();
16134
+ async function toDisplayableImagePath(src) {
16135
+ if (!import_node_path17.default.isAbsolute(src)) {
16136
+ return src;
16137
+ }
16138
+ const ext = import_node_path17.default.extname(src);
16139
+ if (ext) {
16140
+ return src;
16141
+ }
16142
+ try {
16143
+ const stat = await import_node_fs12.promises.stat(src);
16144
+ if (!stat.isFile()) {
16145
+ return src;
16146
+ }
16147
+ const fh = await import_node_fs12.promises.open(src, "r");
16148
+ try {
16149
+ const buf = Buffer.alloc(32);
16150
+ const { bytesRead } = await fh.read(buf, 0, 32, 0);
16151
+ const header = buf.subarray(0, bytesRead);
16152
+ const guessedExt = guessImageExtension(header);
16153
+ if (!guessedExt) {
16154
+ return src;
16155
+ }
16156
+ const cacheDir = import_node_path17.default.join(
16157
+ import_node_os7.default.homedir(),
16158
+ ".pmate",
16159
+ "messages",
16160
+ "images"
16161
+ );
16162
+ await import_node_fs12.promises.mkdir(cacheDir, { recursive: true });
16163
+ const base = (0, import_node_crypto4.createHash)("sha1").update(src).digest("hex");
16164
+ const displayPath = import_node_path17.default.join(cacheDir, `${base}.${guessedExt}`);
16165
+ await import_node_fs12.promises.rm(displayPath, { force: true }).catch(() => void 0);
16166
+ await import_node_fs12.promises.copyFile(src, displayPath);
16167
+ return displayPath;
16168
+ } finally {
16169
+ await fh.close();
16170
+ }
16171
+ } catch {
16172
+ return src;
16173
+ }
16226
16174
  }
16227
- function pad2(value) {
16228
- return String(value).padStart(2, "0");
16175
+ function guessImageExtension(header) {
16176
+ if (header.length >= 3 && header[0] === 255 && header[1] === 216 && header[2] === 255) {
16177
+ return "jpg";
16178
+ }
16179
+ if (header.length >= 8 && header[0] === 137 && header[1] === 80 && header[2] === 78 && header[3] === 71) {
16180
+ return "png";
16181
+ }
16182
+ if (header.length >= 4 && header[0] === 71 && header[1] === 73 && header[2] === 70 && header[3] === 56) {
16183
+ return "gif";
16184
+ }
16185
+ if (header.length >= 12 && header.subarray(0, 4).toString("ascii") === "RIFF" && header.subarray(8, 12).toString("ascii") === "WEBP") {
16186
+ return "webp";
16187
+ }
16188
+ return null;
16229
16189
  }
16230
16190
 
16231
16191
  // src/commands/AgentCommandHandler.ts
16232
- var import_node_fs12 = require("fs");
16233
- var import_node_path17 = __toESM(require("path"));
16192
+ var import_node_fs13 = require("fs");
16193
+ var import_node_path18 = __toESM(require("path"));
16234
16194
  init_AgentLlmClient();
16235
16195
  init_sessionStore();
16236
16196
 
@@ -16238,7 +16198,7 @@ init_sessionStore();
16238
16198
  var STORE_LOG_VERSION = 1;
16239
16199
  var LOG_KIND_TABLE = 1e4;
16240
16200
  var LOG_KIND_MAPPING = 6003;
16241
- function createHash3() {
16201
+ function createHash4() {
16242
16202
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
16243
16203
  }
16244
16204
  function createDescriptor(input) {
@@ -16263,8 +16223,8 @@ function descriptorPathSegments(descriptor) {
16263
16223
  return ["chains", normalized.chain, "namespaces", normalized.ns, normalized.kind, normalized.name];
16264
16224
  }
16265
16225
  function buildPathUrl(baseUrl, pathSegments, query) {
16266
- const path27 = `/${pathSegments.map((segment) => encodeURIComponent(segment)).join("/")}`;
16267
- const url = new URL(path27, baseUrl);
16226
+ const path28 = `/${pathSegments.map((segment) => encodeURIComponent(segment)).join("/")}`;
16227
+ const url = new URL(path28, baseUrl);
16268
16228
  if (query) {
16269
16229
  for (const [key, value] of Object.entries(query)) {
16270
16230
  url.searchParams.set(key, String(value));
@@ -16377,7 +16337,7 @@ var Namespace = class {
16377
16337
  },
16378
16338
  appendRow: async (data) => {
16379
16339
  const log = {
16380
- hash: createHash3(),
16340
+ hash: createHash4(),
16381
16341
  t: Date.now(),
16382
16342
  kind: LOG_KIND_TABLE,
16383
16343
  topic: descriptorToTopic(descriptor),
@@ -16389,7 +16349,7 @@ var Namespace = class {
16389
16349
  updateRow: async (data) => {
16390
16350
  const { id, ...value } = data;
16391
16351
  const log = {
16392
- hash: createHash3(),
16352
+ hash: createHash4(),
16393
16353
  t: Date.now(),
16394
16354
  kind: LOG_KIND_TABLE,
16395
16355
  topic: descriptorToTopic(descriptor),
@@ -16400,7 +16360,7 @@ var Namespace = class {
16400
16360
  },
16401
16361
  deleteRow: async (id) => {
16402
16362
  const log = {
16403
- hash: createHash3(),
16363
+ hash: createHash4(),
16404
16364
  t: Date.now(),
16405
16365
  kind: LOG_KIND_TABLE,
16406
16366
  topic: descriptorToTopic(descriptor),
@@ -16443,7 +16403,7 @@ var Namespace = class {
16443
16403
  },
16444
16404
  set: async (key, value) => {
16445
16405
  const log = {
16446
- hash: createHash3(),
16406
+ hash: createHash4(),
16447
16407
  t: Date.now(),
16448
16408
  kind: LOG_KIND_MAPPING,
16449
16409
  topic: descriptorToTopic(descriptor),
@@ -16454,7 +16414,7 @@ var Namespace = class {
16454
16414
  },
16455
16415
  delete: async (key) => {
16456
16416
  const log = {
16457
- hash: createHash3(),
16417
+ hash: createHash4(),
16458
16418
  t: Date.now(),
16459
16419
  kind: LOG_KIND_MAPPING,
16460
16420
  topic: descriptorToTopic(descriptor),
@@ -16696,11 +16656,11 @@ var AgentCommandHandler = class {
16696
16656
  }).token;
16697
16657
  }
16698
16658
  readJsonFile(filePath) {
16699
- const absolutePath = import_node_path17.default.resolve(process.cwd(), filePath);
16700
- if (!(0, import_node_fs12.existsSync)(absolutePath)) {
16659
+ const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
16660
+ if (!(0, import_node_fs13.existsSync)(absolutePath)) {
16701
16661
  throw new Error(`JSON file not found: ${absolutePath}`);
16702
16662
  }
16703
- const raw = (0, import_node_fs12.readFileSync)(absolutePath, "utf8");
16663
+ const raw = (0, import_node_fs13.readFileSync)(absolutePath, "utf8");
16704
16664
  try {
16705
16665
  return JSON.parse(raw);
16706
16666
  } catch (error) {
@@ -16711,7 +16671,7 @@ var AgentCommandHandler = class {
16711
16671
  readJsonObjectFile(filePath) {
16712
16672
  const parsed = this.readJsonFile(filePath);
16713
16673
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
16714
- const absolutePath = import_node_path17.default.resolve(process.cwd(), filePath);
16674
+ const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
16715
16675
  throw new Error(`Invalid JSON in ${absolutePath}: expected an object`);
16716
16676
  }
16717
16677
  return parsed;
@@ -16795,8 +16755,8 @@ var AgentCommandHandler = class {
16795
16755
  };
16796
16756
 
16797
16757
  // src/commands/RunnerCommandHandler.ts
16798
- var import_node_fs13 = require("fs");
16799
- var import_node_path18 = __toESM(require("path"));
16758
+ var import_node_fs14 = require("fs");
16759
+ var import_node_path19 = __toESM(require("path"));
16800
16760
  init_sessionStore();
16801
16761
  init_namespacedRef();
16802
16762
  var RunnerCommandHandler = class {
@@ -16891,11 +16851,11 @@ var RunnerCommandHandler = class {
16891
16851
  }).token;
16892
16852
  }
16893
16853
  readJsonFile(filePath) {
16894
- const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
16895
- if (!(0, import_node_fs13.existsSync)(absolutePath)) {
16854
+ const absolutePath = import_node_path19.default.resolve(process.cwd(), filePath);
16855
+ if (!(0, import_node_fs14.existsSync)(absolutePath)) {
16896
16856
  throw new Error(`JSON file not found: ${absolutePath}`);
16897
16857
  }
16898
- const raw = (0, import_node_fs13.readFileSync)(absolutePath, "utf8");
16858
+ const raw = (0, import_node_fs14.readFileSync)(absolutePath, "utf8");
16899
16859
  try {
16900
16860
  return JSON.parse(raw);
16901
16861
  } catch (error) {
@@ -17014,8 +16974,8 @@ var NsCommandHandler = class {
17014
16974
  };
17015
16975
 
17016
16976
  // src/commands/StoreCommandHandler.ts
17017
- var import_node_fs14 = require("fs");
17018
- var import_node_path19 = __toESM(require("path"));
16977
+ var import_node_fs15 = require("fs");
16978
+ var import_node_path20 = __toESM(require("path"));
17019
16979
  var StoreCommandHandler = class {
17020
16980
  async handle(args) {
17021
16981
  if (args.scope === "namespace") {
@@ -17157,11 +17117,11 @@ var StoreCommandHandler = class {
17157
17117
  return payload.data ?? [];
17158
17118
  }
17159
17119
  readJsonFile(filePath) {
17160
- const absolutePath = import_node_path19.default.resolve(process.cwd(), filePath);
17161
- if (!(0, import_node_fs14.existsSync)(absolutePath)) {
17120
+ const absolutePath = import_node_path20.default.resolve(process.cwd(), filePath);
17121
+ if (!(0, import_node_fs15.existsSync)(absolutePath)) {
17162
17122
  throw new Error(`JSON file not found: ${absolutePath}`);
17163
17123
  }
17164
- const raw = (0, import_node_fs14.readFileSync)(absolutePath, "utf8");
17124
+ const raw = (0, import_node_fs15.readFileSync)(absolutePath, "utf8");
17165
17125
  try {
17166
17126
  return JSON.parse(raw);
17167
17127
  } catch (error) {
@@ -17213,13 +17173,13 @@ var StoreCommandHandler = class {
17213
17173
  };
17214
17174
 
17215
17175
  // src/commands/AppCommandHandler.ts
17216
- var import_node_fs16 = require("fs");
17217
- var import_node_path21 = __toESM(require("path"));
17176
+ var import_node_fs17 = require("fs");
17177
+ var import_node_path22 = __toESM(require("path"));
17218
17178
  init_sessionStore();
17219
17179
 
17220
17180
  // src/appIcon.ts
17221
- var import_node_fs15 = require("fs");
17222
- var import_node_path20 = __toESM(require("path"));
17181
+ var import_node_fs16 = require("fs");
17182
+ var import_node_path21 = __toESM(require("path"));
17223
17183
  var import_sharp = __toESM(require("sharp"));
17224
17184
  init_namespacedRef();
17225
17185
  var ANDROID_ICON_SPECS = [
@@ -17240,33 +17200,19 @@ var IOS_ICON_SPECS = [
17240
17200
  var pngToIco = require("png-to-ico").default;
17241
17201
  function normalizeAppIcon(icon, cwd) {
17242
17202
  if (typeof icon !== "string" || !icon.trim()) {
17243
- throw new Error("App icon must be a non-empty SVG string or .svg file path.");
17203
+ throw new Error("App icon must be a non-empty http(s) URL.");
17244
17204
  }
17245
17205
  const trimmed = icon.trim();
17246
17206
  if (looksLikeSvgMarkup(trimmed)) {
17247
- return trimmed;
17207
+ throw new Error("App icon cannot be inline SVG. Upload the SVG to OSS first and use its http(s) URL.");
17248
17208
  }
17249
17209
  if (trimmed.startsWith("data:")) {
17250
- return normalizeSvgDataUrl(trimmed);
17210
+ throw new Error("App icon cannot be a data URL. Upload the SVG to OSS first and use its http(s) URL.");
17251
17211
  }
17252
17212
  if (/^https?:\/\//i.test(trimmed)) {
17253
- throw new Error("App icon must be SVG source, not a remote URL.");
17254
- }
17255
- const absolutePath = import_node_path20.default.resolve(cwd, trimmed);
17256
- if (!(0, import_node_fs15.existsSync)(absolutePath)) {
17257
- if (trimmed.toLowerCase().endsWith(".svg")) {
17258
- throw new Error(`App icon SVG file not found: ${absolutePath}`);
17259
- }
17260
- throw new Error("App icon must be inline SVG, an SVG data URL, or a .svg file path.");
17261
- }
17262
- if (import_node_path20.default.extname(absolutePath).toLowerCase() !== ".svg") {
17263
- throw new Error(`App icon file must use the .svg extension: ${absolutePath}`);
17264
- }
17265
- const svg = (0, import_node_fs15.readFileSync)(absolutePath, "utf8").trim();
17266
- if (!looksLikeSvgMarkup(svg)) {
17267
- throw new Error(`App icon file is not valid SVG: ${absolutePath}`);
17213
+ return trimmed;
17268
17214
  }
17269
- return svg;
17215
+ throw new Error("App icon must be an http(s) URL. Upload SVG files to OSS first and use the public link.");
17270
17216
  }
17271
17217
  function prepareAppPayload(payload, cwd) {
17272
17218
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
@@ -17287,13 +17233,13 @@ function createAppIconExportPlans(input) {
17287
17233
  if (!input.outDir) {
17288
17234
  throw new Error("App icon preset export requires --out-dir.");
17289
17235
  }
17290
- const outDir = import_node_path20.default.resolve(input.cwd, input.outDir);
17291
- (0, import_node_fs15.mkdirSync)(outDir, { recursive: true });
17236
+ const outDir = import_node_path21.default.resolve(input.cwd, input.outDir);
17237
+ (0, import_node_fs16.mkdirSync)(outDir, { recursive: true });
17292
17238
  return specs.map((spec) => ({
17293
17239
  width: spec.width,
17294
17240
  height: spec.height,
17295
17241
  format: "png",
17296
- outputPath: import_node_path20.default.join(
17242
+ outputPath: import_node_path21.default.join(
17297
17243
  outDir,
17298
17244
  `${namespace}-${objectId}-${spec.name}-${spec.width}x${spec.height}.png`
17299
17245
  )
@@ -17306,8 +17252,8 @@ function createAppIconExportPlans(input) {
17306
17252
  if (!input.output) {
17307
17253
  throw new Error("Single-size app icon export requires --output.");
17308
17254
  }
17309
- const resolvedOutput = import_node_path20.default.resolve(input.cwd, input.output);
17310
- (0, import_node_fs15.mkdirSync)(import_node_path20.default.dirname(resolvedOutput), { recursive: true });
17255
+ const resolvedOutput = import_node_path21.default.resolve(input.cwd, input.output);
17256
+ (0, import_node_fs16.mkdirSync)(import_node_path21.default.dirname(resolvedOutput), { recursive: true });
17311
17257
  return [
17312
17258
  {
17313
17259
  width: input.width,
@@ -17317,11 +17263,34 @@ function createAppIconExportPlans(input) {
17317
17263
  }
17318
17264
  ];
17319
17265
  }
17320
- async function exportAppIcon(svg, plans) {
17266
+ async function exportAppIcon(icon, plans) {
17267
+ const svg = await resolveAppIconSvg(icon);
17321
17268
  for (const plan of plans) {
17322
17269
  const bytes = await renderAppIcon(svg, plan.width, plan.height, plan.format);
17323
- (0, import_node_fs15.writeFileSync)(plan.outputPath, bytes);
17270
+ (0, import_node_fs16.writeFileSync)(plan.outputPath, bytes);
17271
+ }
17272
+ }
17273
+ async function resolveAppIconSvg(icon) {
17274
+ const trimmed = icon.trim();
17275
+ if (looksLikeSvgMarkup(trimmed)) {
17276
+ return trimmed;
17277
+ }
17278
+ if (!/^https?:\/\//i.test(trimmed)) {
17279
+ throw new Error("App icon export requires inline SVG or an http(s) SVG URL.");
17280
+ }
17281
+ const response = await fetch(trimmed);
17282
+ if (!response.ok) {
17283
+ throw new Error(`Failed to fetch app icon SVG: ${response.status} ${response.statusText}`.trim());
17284
+ }
17285
+ const contentType = response.headers.get("content-type")?.toLowerCase() || "";
17286
+ const svg = (await response.text()).trim();
17287
+ if (contentType && !contentType.includes("image/svg+xml") && !looksLikeSvgMarkup(svg)) {
17288
+ throw new Error(`App icon URL must return SVG content. Received: ${contentType}`);
17324
17289
  }
17290
+ if (!looksLikeSvgMarkup(svg)) {
17291
+ throw new Error("App icon URL does not contain valid SVG markup.");
17292
+ }
17293
+ return svg;
17325
17294
  }
17326
17295
  async function renderAppIcon(svg, width, height, format) {
17327
17296
  if (format === "svg") {
@@ -17343,23 +17312,6 @@ async function renderAppIcon(svg, width, height, format) {
17343
17312
  function looksLikeSvgMarkup(value) {
17344
17313
  return /<svg[\s>]/i.test(value);
17345
17314
  }
17346
- function normalizeSvgDataUrl(value) {
17347
- const match = /^data:([^;,]+)?(?:;charset=[^;,]+)?(?:;(base64))?,(.*)$/i.exec(value);
17348
- if (!match) {
17349
- throw new Error("Invalid app icon data URL.");
17350
- }
17351
- const mimeType = (match[1] || "").toLowerCase();
17352
- if (mimeType !== "image/svg+xml") {
17353
- throw new Error(`App icon data URL must be image/svg+xml. Received: ${mimeType || "unknown"}`);
17354
- }
17355
- const payload = match[3] || "";
17356
- const decoded = match[2] ? Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
17357
- const svg = decoded.trim();
17358
- if (!looksLikeSvgMarkup(svg)) {
17359
- throw new Error("App icon data URL does not contain valid SVG markup.");
17360
- }
17361
- return svg;
17362
- }
17363
17315
 
17364
17316
  // src/commands/AppCommandHandler.ts
17365
17317
  init_namespacedRef();
@@ -17375,7 +17327,12 @@ var AppCommandHandler = class {
17375
17327
  "GET",
17376
17328
  "/apps"
17377
17329
  );
17378
- const items = args.namespace ? response.items.filter((item) => item.namespace === args.namespace) : response.items;
17330
+ const items = response.items.filter((item) => {
17331
+ if (!args.all && item.status !== "active") {
17332
+ return false;
17333
+ }
17334
+ return args.namespace ? item.namespace === args.namespace : true;
17335
+ });
17379
17336
  this.renderList(items, args.json);
17380
17337
  return;
17381
17338
  }
@@ -17511,10 +17468,10 @@ var AppCommandHandler = class {
17511
17468
  }
17512
17469
  readJsonFile(filePath) {
17513
17470
  const absolutePath = this.resolveFilePath(filePath);
17514
- if (!(0, import_node_fs16.existsSync)(absolutePath)) {
17471
+ if (!(0, import_node_fs17.existsSync)(absolutePath)) {
17515
17472
  throw new Error(`JSON file not found: ${absolutePath}`);
17516
17473
  }
17517
- const raw = (0, import_node_fs16.readFileSync)(absolutePath, "utf8");
17474
+ const raw = (0, import_node_fs17.readFileSync)(absolutePath, "utf8");
17518
17475
  try {
17519
17476
  return JSON.parse(raw);
17520
17477
  } catch (error) {
@@ -17524,10 +17481,10 @@ var AppCommandHandler = class {
17524
17481
  }
17525
17482
  preparePayload(filePath) {
17526
17483
  const absolutePath = this.resolveFilePath(filePath);
17527
- return prepareAppPayload(this.readJsonFile(filePath), import_node_path21.default.dirname(absolutePath));
17484
+ return prepareAppPayload(this.readJsonFile(filePath), import_node_path22.default.dirname(absolutePath));
17528
17485
  }
17529
17486
  resolveFilePath(filePath) {
17530
- return import_node_path21.default.resolve(process.cwd(), filePath);
17487
+ return import_node_path22.default.resolve(process.cwd(), filePath);
17531
17488
  }
17532
17489
  async request(baseUrl, token, method, pathname, body) {
17533
17490
  const response = await fetch(`${baseUrl}${pathname}`, {
@@ -17601,15 +17558,15 @@ function readNamespaceFromPayload(payload) {
17601
17558
  }
17602
17559
 
17603
17560
  // src/commands/ServiceCommandHandler.ts
17604
- var import_node_fs18 = require("fs");
17561
+ var import_node_fs19 = require("fs");
17605
17562
  var import_promises5 = require("fs/promises");
17606
- var import_node_path23 = __toESM(require("path"));
17563
+ var import_node_path24 = __toESM(require("path"));
17607
17564
  var import_promises6 = require("readline/promises");
17608
17565
 
17609
17566
  // src/services/ServiceRuntimeRunner.ts
17610
- var import_node_fs17 = require("fs");
17611
- var import_node_os7 = __toESM(require("os"));
17612
- var import_node_path22 = __toESM(require("path"));
17567
+ var import_node_fs18 = require("fs");
17568
+ var import_node_os8 = __toESM(require("os"));
17569
+ var import_node_path23 = __toESM(require("path"));
17613
17570
  var import_node_child_process10 = require("child_process");
17614
17571
  var import_node_readline = require("readline");
17615
17572
  var import_chalk3 = __toESM(require("chalk"));
@@ -17774,14 +17731,14 @@ var ServiceRuntimeRunner = class {
17774
17731
  }
17775
17732
  resolveRepoRoot(service, cwd) {
17776
17733
  if (cwd) {
17777
- return import_node_path22.default.resolve(process.cwd(), cwd);
17734
+ return import_node_path23.default.resolve(process.cwd(), cwd);
17778
17735
  }
17779
17736
  const repository = this.getType(service) === "vite" || this.getType(service) === "static" ? this.getSite(service).repository?.trim() : this.getType(service) === "ios" || this.getType(service) === "android" ? void 0 : this.getNetwork(service).repository?.trim();
17780
17737
  if (repository) {
17781
17738
  const repoName = repository.replace(/\/+$/, "").split("/").pop()?.replace(/\.git$/i, "");
17782
17739
  if (repoName) {
17783
- const candidate = import_node_path22.default.join(import_node_os7.default.homedir(), "dev", "pmate", repoName);
17784
- if ((0, import_node_fs17.existsSync)(candidate)) {
17740
+ const candidate = import_node_path23.default.join(import_node_os8.default.homedir(), "dev", "pmate", repoName);
17741
+ if ((0, import_node_fs18.existsSync)(candidate)) {
17785
17742
  return candidate;
17786
17743
  }
17787
17744
  }
@@ -17794,12 +17751,12 @@ var ServiceRuntimeRunner = class {
17794
17751
  if (!dir) {
17795
17752
  throw new Error(`Missing service dir for ${service.id}`);
17796
17753
  }
17797
- return import_node_path22.default.resolve(repoRoot, dir);
17754
+ return import_node_path23.default.resolve(repoRoot, dir);
17798
17755
  }
17799
17756
  async deployVite(service, options) {
17800
17757
  const appDir = this.resolveLocalDir(service, options.cwd);
17801
- const packageJsonPath = import_node_path22.default.join(appDir, "package.json");
17802
- if (!(0, import_node_fs17.existsSync)(packageJsonPath)) {
17758
+ const packageJsonPath = import_node_path23.default.join(appDir, "package.json");
17759
+ if (!(0, import_node_fs18.existsSync)(packageJsonPath)) {
17803
17760
  throw new Error(`No package.json found at ${packageJsonPath}`);
17804
17761
  }
17805
17762
  const pkg2 = this.loadPackageJson(packageJsonPath);
@@ -17808,8 +17765,8 @@ var ServiceRuntimeRunner = class {
17808
17765
  throw new Error(`Missing package name in ${packageJsonPath}`);
17809
17766
  }
17810
17767
  await this.runCommand("pnpm", ["--filter", pkgName, "build"], this.resolveRepoRoot(service, options.cwd));
17811
- const distDir = import_node_path22.default.join(appDir, "dist");
17812
- if (!(0, import_node_fs17.existsSync)(distDir)) {
17768
+ const distDir = import_node_path23.default.join(appDir, "dist");
17769
+ if (!(0, import_node_fs18.existsSync)(distDir)) {
17813
17770
  throw new Error(`No dist directory found at ${distDir}`);
17814
17771
  }
17815
17772
  const site = this.getSite(service);
@@ -17821,8 +17778,8 @@ var ServiceRuntimeRunner = class {
17821
17778
  }
17822
17779
  async deployStatic(service, options) {
17823
17780
  const appDir = this.resolveLocalDir(service, options.cwd);
17824
- const srcDir = import_node_path22.default.join(appDir, "src");
17825
- if (!(0, import_node_fs17.existsSync)(srcDir)) {
17781
+ const srcDir = import_node_path23.default.join(appDir, "src");
17782
+ if (!(0, import_node_fs18.existsSync)(srcDir)) {
17826
17783
  throw new Error(`No src directory found at ${srcDir}`);
17827
17784
  }
17828
17785
  const site = this.getSite(service);
@@ -17942,7 +17899,7 @@ var ServiceRuntimeRunner = class {
17942
17899
  const serverAddress = await resolveServerAddress(server);
17943
17900
  const templateName = exposeType === "websocket" ? "nginx.ws.template" : "nginx.rest.template";
17944
17901
  const templatePath = this.resolveTemplatePath(templateName);
17945
- const template = (0, import_node_fs17.readFileSync)(templatePath, "utf8");
17902
+ const template = (0, import_node_fs18.readFileSync)(templatePath, "utf8");
17946
17903
  const host = `${subdomain}.${("domain" in network ? network.domain?.trim() : void 0) || "pmate.chat"}`;
17947
17904
  const rendered = template.replace(/\$\{\{PORT\}\}/g, String(port)).replace(/\$\{\{HOSTS\}\}/g, host).replace(/\$\{\{HOST\}\}/g, host);
17948
17905
  const remotePath = `/etc/nginx/sites-enabled/${subdomain}.conf`;
@@ -17974,11 +17931,11 @@ var ServiceRuntimeRunner = class {
17974
17931
  }
17975
17932
  if (config.ensurePackageJson) {
17976
17933
  const appDir = this.resolveLocalDir(service, options.cwd);
17977
- const packageJsonPath = import_node_path22.default.join(appDir, "package.json");
17978
- if (!(0, import_node_fs17.existsSync)(packageJsonPath)) {
17934
+ const packageJsonPath = import_node_path23.default.join(appDir, "package.json");
17935
+ if (!(0, import_node_fs18.existsSync)(packageJsonPath)) {
17979
17936
  throw new Error(`Missing package.json at ${packageJsonPath}`);
17980
17937
  }
17981
- const pkgStat = (0, import_node_fs17.statSync)(packageJsonPath);
17938
+ const pkgStat = (0, import_node_fs18.statSync)(packageJsonPath);
17982
17939
  if (!pkgStat.isFile()) {
17983
17940
  throw new Error(`package.json is not a file at ${packageJsonPath}`);
17984
17941
  }
@@ -18402,9 +18359,9 @@ var ServiceRuntimeRunner = class {
18402
18359
  return tokens;
18403
18360
  }
18404
18361
  readPathValue(source, pathExpr) {
18405
- const path27 = pathExpr.split(".").map((segment) => segment.trim()).filter(Boolean);
18362
+ const path28 = pathExpr.split(".").map((segment) => segment.trim()).filter(Boolean);
18406
18363
  let cursor = source;
18407
- for (const segment of path27) {
18364
+ for (const segment of path28) {
18408
18365
  if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) {
18409
18366
  return void 0;
18410
18367
  }
@@ -18447,12 +18404,12 @@ var ServiceRuntimeRunner = class {
18447
18404
  }
18448
18405
  resolveTemplatePath(templateName) {
18449
18406
  const candidates = [
18450
- import_node_path22.default.join(__dirname, "..", "templates", templateName),
18451
- import_node_path22.default.join(__dirname, "..", "src", "templates", templateName),
18452
- import_node_path22.default.join(__dirname, "templates", templateName)
18407
+ import_node_path23.default.join(__dirname, "..", "templates", templateName),
18408
+ import_node_path23.default.join(__dirname, "..", "src", "templates", templateName),
18409
+ import_node_path23.default.join(__dirname, "templates", templateName)
18453
18410
  ];
18454
18411
  for (const candidate of candidates) {
18455
- if ((0, import_node_fs17.existsSync)(candidate)) {
18412
+ if ((0, import_node_fs18.existsSync)(candidate)) {
18456
18413
  return candidate;
18457
18414
  }
18458
18415
  }
@@ -18484,7 +18441,7 @@ var ServiceRuntimeRunner = class {
18484
18441
  });
18485
18442
  }
18486
18443
  loadPackageJson(packageJsonPath) {
18487
- const raw = (0, import_node_fs17.readFileSync)(packageJsonPath, "utf8");
18444
+ const raw = (0, import_node_fs18.readFileSync)(packageJsonPath, "utf8");
18488
18445
  const parsed = JSON.parse(raw);
18489
18446
  if (!parsed || typeof parsed !== "object") {
18490
18447
  throw new Error(`Invalid package.json at ${packageJsonPath}`);
@@ -18493,7 +18450,7 @@ var ServiceRuntimeRunner = class {
18493
18450
  }
18494
18451
  writePackageJson(packageJsonPath, data) {
18495
18452
  const serialized = JSON.stringify(data, null, 2);
18496
- (0, import_node_fs17.writeFileSync)(packageJsonPath, `${serialized}
18453
+ (0, import_node_fs18.writeFileSync)(packageJsonPath, `${serialized}
18497
18454
  `, "utf8");
18498
18455
  }
18499
18456
  runCommand(command, args, cwd) {
@@ -18830,7 +18787,7 @@ var ServiceCommandHandler = class {
18830
18787
  format: "dotenv"
18831
18788
  }
18832
18789
  );
18833
- const outputPath = import_node_path23.default.resolve(process.cwd(), args.output);
18790
+ const outputPath = import_node_path24.default.resolve(process.cwd(), args.output);
18834
18791
  await (0, import_promises5.writeFile)(outputPath, payload.content, "utf8");
18835
18792
  ui.success(`Wrote env file for ${args.appId} to ${outputPath}`);
18836
18793
  this.renderJson({ ...payload, output: outputPath }, args.json);
@@ -18859,11 +18816,11 @@ var ServiceCommandHandler = class {
18859
18816
  return (baseUrl || process.env.PMATE_APPS_API_BASE_URL || "https://apps-api.pmate.chat").replace(/\/+$/, "");
18860
18817
  }
18861
18818
  readJsonFile(filePath) {
18862
- const absolutePath = import_node_path23.default.resolve(process.cwd(), filePath);
18863
- if (!(0, import_node_fs18.existsSync)(absolutePath)) {
18819
+ const absolutePath = import_node_path24.default.resolve(process.cwd(), filePath);
18820
+ if (!(0, import_node_fs19.existsSync)(absolutePath)) {
18864
18821
  throw new Error(`JSON file not found: ${absolutePath}`);
18865
18822
  }
18866
- const raw = (0, import_node_fs18.readFileSync)(absolutePath, "utf8");
18823
+ const raw = (0, import_node_fs19.readFileSync)(absolutePath, "utf8");
18867
18824
  try {
18868
18825
  return JSON.parse(raw);
18869
18826
  } catch (error) {
@@ -19203,8 +19160,8 @@ var RoleCommandHandler = class {
19203
19160
  };
19204
19161
 
19205
19162
  // src/commands/AccountCommandHandler.ts
19206
- var import_node_fs19 = require("fs");
19207
- var import_node_path24 = __toESM(require("path"));
19163
+ var import_node_fs20 = require("fs");
19164
+ var import_node_path25 = __toESM(require("path"));
19208
19165
  init_sessionStore();
19209
19166
  var AccountCommandHandler = class {
19210
19167
  async handle(args) {
@@ -19452,10 +19409,10 @@ var AccountCommandHandler = class {
19452
19409
  throw new Error("Missing visible apps input");
19453
19410
  }
19454
19411
  const absolutePath = this.resolveFilePath(args.filePath);
19455
- if (!(0, import_node_fs19.existsSync)(absolutePath)) {
19412
+ if (!(0, import_node_fs20.existsSync)(absolutePath)) {
19456
19413
  throw new Error(`JSON file not found: ${absolutePath}`);
19457
19414
  }
19458
- const raw = (0, import_node_fs19.readFileSync)(absolutePath, "utf8");
19415
+ const raw = (0, import_node_fs20.readFileSync)(absolutePath, "utf8");
19459
19416
  let parsed;
19460
19417
  try {
19461
19418
  parsed = JSON.parse(raw);
@@ -19469,7 +19426,7 @@ var AccountCommandHandler = class {
19469
19426
  return parsed;
19470
19427
  }
19471
19428
  resolveFilePath(filePath) {
19472
- return import_node_path24.default.resolve(process.cwd(), filePath);
19429
+ return import_node_path25.default.resolve(process.cwd(), filePath);
19473
19430
  }
19474
19431
  };
19475
19432
  function encodePathSegment(value) {
@@ -19477,8 +19434,8 @@ function encodePathSegment(value) {
19477
19434
  }
19478
19435
 
19479
19436
  // src/commands/OrgCommandHandler.ts
19480
- var import_node_fs20 = require("fs");
19481
- var import_node_path25 = __toESM(require("path"));
19437
+ var import_node_fs21 = require("fs");
19438
+ var import_node_path26 = __toESM(require("path"));
19482
19439
  init_sessionStore();
19483
19440
  var OrgCommandHandler = class {
19484
19441
  async handle(args) {
@@ -19649,11 +19606,11 @@ var OrgCommandHandler = class {
19649
19606
  if (!filePath) {
19650
19607
  throw new Error(`Missing ${itemLabel} input`);
19651
19608
  }
19652
- const absolutePath = import_node_path25.default.resolve(process.cwd(), filePath);
19653
- if (!(0, import_node_fs20.existsSync)(absolutePath)) {
19609
+ const absolutePath = import_node_path26.default.resolve(process.cwd(), filePath);
19610
+ if (!(0, import_node_fs21.existsSync)(absolutePath)) {
19654
19611
  throw new Error(`JSON file not found: ${absolutePath}`);
19655
19612
  }
19656
- const raw = (0, import_node_fs20.readFileSync)(absolutePath, "utf8");
19613
+ const raw = (0, import_node_fs21.readFileSync)(absolutePath, "utf8");
19657
19614
  let parsed;
19658
19615
  try {
19659
19616
  parsed = JSON.parse(raw);
@@ -20552,6 +20509,7 @@ function parseAppArgs(tokens) {
20552
20509
  };
20553
20510
  if (action === "list") {
20554
20511
  let namespace;
20512
+ let all = false;
20555
20513
  while (rest.length > 0) {
20556
20514
  const token = rest.shift();
20557
20515
  switch (token) {
@@ -20559,6 +20517,9 @@ function parseAppArgs(tokens) {
20559
20517
  case "--namespace":
20560
20518
  namespace = requireValue5(rest, token);
20561
20519
  break;
20520
+ case "--all":
20521
+ all = true;
20522
+ break;
20562
20523
  case "--base-url":
20563
20524
  baseUrl = requireValue5(rest, token);
20564
20525
  break;
@@ -20569,7 +20530,7 @@ function parseAppArgs(tokens) {
20569
20530
  throw new Error(`Unknown app list option: ${token}`);
20570
20531
  }
20571
20532
  }
20572
- return { type: "app" /* App */, action, namespace, baseUrl, json };
20533
+ return { type: "app" /* App */, action, namespace, all, baseUrl, json };
20573
20534
  }
20574
20535
  if (action === "view") {
20575
20536
  const rawRef = rest.shift();
@@ -22138,7 +22099,7 @@ function requireValue11(tokens, option) {
22138
22099
 
22139
22100
  // src/index.ts
22140
22101
  var pkg = JSON.parse(
22141
- (0, import_node_fs21.readFileSync)(import_node_path26.default.resolve(__dirname, "..", "package.json"), "utf8")
22102
+ (0, import_node_fs22.readFileSync)(import_node_path27.default.resolve(__dirname, "..", "package.json"), "utf8")
22142
22103
  );
22143
22104
  var HELP_TEXT = [
22144
22105
  import_chalk4.default.bold(`pmate v${pkg.version}`),
@@ -22281,7 +22242,7 @@ var HELP_TEXT = [
22281
22242
  ` ${import_chalk4.default.gray(" kv list|get|exists|set|delete <name> [options]")}`,
22282
22243
  ` ${import_chalk4.default.gray(" defaults: chain=pmate namespace=pmate env base URLs from BLOCKCHAIN_BASE_URL / INDEXER_BASE_URL")}`,
22283
22244
  ` ${import_chalk4.default.cyan("app")} Manage app registry entries via apps-api`,
22284
- ` ${import_chalk4.default.gray(" list [--ns <namespace>] [--base-url <url>] [--json]")}`,
22245
+ ` ${import_chalk4.default.gray(" list [--ns <namespace>] [--all] [--base-url <url>] [--json]")}`,
22285
22246
  ` ${import_chalk4.default.gray(" get <ns:objectId> [--base-url <url>] [--json]")}`,
22286
22247
  ` ${import_chalk4.default.gray(" view <ns:objectId> [--base-url <url>]")}`,
22287
22248
  ` ${import_chalk4.default.gray(" create --file <path> [--base-url <url>] [--json]")}`,