« Lis ma conversation avec Maman » — chat.db, en lecture, honnêtement.
Atlas, grand chantier n°1, 25 août 2026. imessage_get_conversation était
déclaré depuis des mois sans exécuteur. L'outil vit ici : données
strictement locales (chat.db en lecture seule), le petit nom résolu par le
même résolveur que messages_send, et les trois issues explicites de la
maison — trouvé, rien, ou illisible-avec-le-remède (l'Accès complet au
disque manque encore sur cette machine : l'outil l'avoue, il ne se tait
pas).
Bases: BaseTool
La conversation Messages avec quelqu'un, lue dans chat.db.
lire_conversation(
identifiant: str,
*,
limite: int = 30,
db_path: str = _DB_PAR_DEFAUT,
) -> dict
Les derniers messages avec un correspondant — issues explicites.
{"issue": "unreadable"|"not_found"|"found", "messages": [...],
"sans_texte": n}. Les rangées au texte NULL (attributedBody des macOS
récents) sont comptées, pas inventées.
Source code in src/diapason/tools/imessage_tools.py
| def lire_conversation(
identifiant: str, *, limite: int = 30, db_path: str = _DB_PAR_DEFAUT
) -> dict:
"""Les derniers messages avec un correspondant — issues explicites.
{"issue": "unreadable"|"not_found"|"found", "messages": [...],
"sans_texte": n}. Les rangées au texte NULL (attributedBody des macOS
récents) sont comptées, pas inventées.
"""
try:
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
except sqlite3.OperationalError as exc:
return {"issue": "unreadable", "detail": str(exc), "messages": []}
try:
lignes = conn.execute(
"SELECT m.text, m.is_from_me, m.date "
"FROM message m "
"JOIN chat_message_join cmj ON cmj.message_id = m.ROWID "
"JOIN chat c ON c.ROWID = cmj.chat_id "
"WHERE c.chat_identifier = ? "
"ORDER BY m.date DESC LIMIT ?",
(identifiant.strip(), max(1, limite)),
).fetchall()
except sqlite3.OperationalError as exc:
# TCC a deux portes : l'ouverture peut réussir et la PREMIÈRE
# lecture échouer (leçon du connecteur imessage).
return {"issue": "unreadable", "detail": str(exc), "messages": []}
finally:
conn.close()
if not lignes:
return {"issue": "not_found", "messages": [], "sans_texte": 0}
from diapason.connectors.imessage import _apple_ts_to_datetime
messages = []
sans_texte = 0
for texte, de_moi, date_ns in reversed(lignes):
if not texte:
sans_texte += 1
continue
messages.append(
{
"texte": texte,
"de_moi": bool(de_moi),
"quand": _apple_ts_to_datetime(int(date_ns or 0)).isoformat(
timespec="minutes"
),
}
)
return {"issue": "found", "messages": messages, "sans_texte": sans_texte}
|