imsg-mcp 1.9.0 → 1.11.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and follows [Semantic Versioning](https://semver.org/).
5
5
 
6
+ # [1.11.0](https://github.com/george43g/imsg-mcp/compare/v1.10.0...v1.11.0) (2026-07-21)
7
+
8
+
9
+ ### Features
10
+
11
+ * **db+tui:** parse message edit history and show it in the drawer ([e4df935](https://github.com/george43g/imsg-mcp/commit/e4df93552f96419bebe50acd241b7d0b74854c9b))
12
+
13
+ # [1.10.0](https://github.com/george43g/imsg-mcp/compare/v1.9.0...v1.10.0) (2026-07-21)
14
+
15
+
16
+ ### Features
17
+
18
+ * **core:** media-intel interpretation service, cache & providers ([d6441de](https://github.com/george43g/imsg-mcp/commit/d6441de0248336f9a1fe04a709a8541c13476527))
19
+
6
20
  # [1.9.0](https://github.com/george43g/imsg-mcp/compare/v1.8.0...v1.9.0) (2026-07-21)
7
21
 
8
22
 
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { createInterface } from "node:readline";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { Command } from "commander";
6
6
  import { c as checkLocalAccess, f as formatAccessReport, J as IMPLEMENTED_TYPES, K as ANALYTIC_INFO, w as installShutdownHandlers, x as registerCleanup, L as looksLikeThreadSlug } from "./shutdown-CQ9wzrxA.js";
7
- import { A as APP_VERSION, t as toYaml } from "./meta-BrYyl7Ls.js";
7
+ import { A as APP_VERSION, t as toYaml } from "./meta-Cl3zjUCl.js";
8
8
  import { spawn } from "node:child_process";
9
9
  import { join, dirname } from "node:path";
10
10
  function distRoot() {
@@ -447,7 +447,7 @@ async function runExportCommand(target, opts) {
447
447
  const { homedir } = await import("node:os");
448
448
  const { dirname: dirname2, join: join2, isAbsolute, resolve } = await import("node:path");
449
449
  const { getContactsDbPaths, getImsgDbPath, getSlugsDbPath } = await import("./shutdown-CQ9wzrxA.js").then((n) => n.a0);
450
- const { IMessageDB } = await import("./imessage-db-vrzopRGT.js").then((n) => n.i);
450
+ const { IMessageDB } = await import("./imessage-db-CdVmw2od.js").then((n) => n.i);
451
451
  const { streamExport } = await import("./exportStream-DgPVRZTZ.js");
452
452
  const { parseUserDate } = await import("./date-parse-DJXMfq3a.js");
453
453
  const format = normalizeFormat(opts.format ?? "md");
@@ -5,7 +5,7 @@ import { createRequire } from "node:module";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { existsSync, readdirSync, mkdirSync } from "node:fs";
7
7
  import { Q as OBJECT_REPLACEMENT_CHAR, p as perf, R as isGroupGuid, S as isGroupChatIdentifier, T as generateThreadSlug, U as Tables, V as AssociatedMessageType, W as macAutoTimestampToDate, X as isReactionType, Y as MAC_EPOCH_OFFSET, Z as NANOS_PER_SECOND, _ as macTimestampToDate$1, $ as parseAssociatedMessageGuid$1 } from "./shutdown-CQ9wzrxA.js";
8
- import { parseBuffer } from "bplist-parser";
8
+ import bplist, { parseBuffer } from "bplist-parser";
9
9
  function normalizePhoneNumber(phone) {
10
10
  const digits = phone.replace(/\D/g, "");
11
11
  if (digits.length === 11 && digits.startsWith("1")) {
@@ -945,6 +945,58 @@ function normalizeRichMetadataText(text) {
945
945
  function pickConversationSnippet(options) {
946
946
  return normalizeSnippetText(options.rawText) ?? normalizeSnippetText(options.parsedText) ?? normalizeSnippetText(options.summaryText);
947
947
  }
948
+ const MAC_EPOCH_OFFSET_SECONDS = 978307200;
949
+ function cocoaDateToDate(d) {
950
+ if (typeof d !== "number" || !Number.isFinite(d)) return null;
951
+ const seconds = Math.abs(d) > 1e15 ? d / 1e9 : d;
952
+ const ms = (seconds + MAC_EPOCH_OFFSET_SECONDS) * 1e3;
953
+ const date = new Date(ms);
954
+ const year = date.getUTCFullYear();
955
+ if (year < 2015 || year > 2100) return null;
956
+ return date;
957
+ }
958
+ function decodeVersionText(t) {
959
+ if (Buffer.isBuffer(t)) return extractAttributedBodyText(t) ?? null;
960
+ if (t instanceof Uint8Array) return extractAttributedBodyText(Buffer.from(t)) ?? null;
961
+ return null;
962
+ }
963
+ function parseEditSummary(root) {
964
+ if (!root || typeof root !== "object") return null;
965
+ const parts = [];
966
+ const ec = root.ec;
967
+ if (ec && typeof ec === "object") {
968
+ for (const [key, value] of Object.entries(ec)) {
969
+ const part = Number.parseInt(key, 10);
970
+ if (!Number.isFinite(part) || !Array.isArray(value)) continue;
971
+ const versions = value.map((v) => {
972
+ const entry = v ?? {};
973
+ return { text: decodeVersionText(entry.t), date: cocoaDateToDate(entry.d) };
974
+ });
975
+ if (versions.length > 0) parts.push({ part, versions });
976
+ }
977
+ parts.sort((a, b) => a.part - b.part);
978
+ }
979
+ const retractedParts = [];
980
+ const rp = root.rp;
981
+ if (Array.isArray(rp)) {
982
+ for (const p of rp) {
983
+ const n = typeof p === "number" ? p : Number.parseInt(String(p), 10);
984
+ if (Number.isFinite(n)) retractedParts.push(n);
985
+ }
986
+ }
987
+ if (parts.length === 0 && retractedParts.length === 0) return null;
988
+ return { parts, retractedParts };
989
+ }
990
+ function extractEditHistory(msi) {
991
+ if (!msi || msi.length === 0) return null;
992
+ try {
993
+ const parsed = bplist.parseBuffer(msi);
994
+ const root = parsed?.[0];
995
+ return parseEditSummary(root);
996
+ } catch {
997
+ return null;
998
+ }
999
+ }
948
1000
  function normalizeText(value) {
949
1001
  const normalized = value?.replace(/\s+/g, " ").trim();
950
1002
  return normalized && normalized.length >= 4 ? normalized : void 0;
@@ -2560,6 +2612,8 @@ class IMessageDB {
2560
2612
  hasAttachments
2561
2613
  });
2562
2614
  const appleAudioTranscript = extractAudioTranscription(raw.attributedBody ?? null);
2615
+ const isEditedMessage = !isUnsent && Boolean(ext.date_edited && ext.date_edited > 0);
2616
+ const editHistory = isEditedMessage && ext.message_summary_info ? extractEditHistory(ext.message_summary_info) ?? void 0 : void 0;
2563
2617
  return {
2564
2618
  id: raw.ROWID,
2565
2619
  guid: raw.guid,
@@ -2585,9 +2639,10 @@ class IMessageDB {
2585
2639
  reactions,
2586
2640
  richContentType,
2587
2641
  richContentSummary,
2588
- isEdited: !isUnsent && Boolean(ext.date_edited && ext.date_edited > 0),
2642
+ isEdited: isEditedMessage,
2589
2643
  isRetracted: isUnsent || Boolean(ext.date_retracted && ext.date_retracted > 0),
2590
2644
  appleAudioTranscript,
2645
+ editHistory,
2591
2646
  hasAttachments,
2592
2647
  attachments
2593
2648
  };
@@ -3124,4 +3179,4 @@ export {
3124
3179
  normalizedPhoneVariants as n,
3125
3180
  rankFuzzy as r
3126
3181
  };
3127
- //# sourceMappingURL=imessage-db-vrzopRGT.js.map
3182
+ //# sourceMappingURL=imessage-db-CdVmw2od.js.map