Editing a `!journal` message now rewrites the entry it created rather
than recording another row. Entries are keyed on their source event id
(new `event_id` column, v2 migration); get_edit() yields that original
id, so the edit is matched back to its row.
`ts` keeps the original send time — it records when the work was logged,
not when the wording was fixed. Confirmation is a 📝 reaction on the
edited message, because replying to an edit event renders as "This event
could not be displayed" in Element and a reply per save is noise.
Supersedes 3dc7eab, which ignored edits outright; updating is what's
actually wanted. Entries predating this have event_id IS NULL and can't
be matched, so editing one is a no-op.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019wNB1sgkcBGijWjKTjtwG8
An edited `!journal ...` message was recorded as a brand-new entry, so
one message edited five times produced five near-identical rows.
Matrix delivers an edit as a fresh m.room.message, and mautrix swaps its
content for `m.new_content` during deserialization
(mautrix/types/event/message.py:393-396), stripping the "* " fallback
prefix. The handler therefore saw something byte-identical to a new
command. Neither @command.passive nor @command.new filters edits, so
guard on evt.content.get_edit() in the plugin.
Also corrects the README quirk that claimed edits could never reach the
bot — it asserted the opposite of the actual behavior.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019wNB1sgkcBGijWjKTjtwG8
Root README orients new contributors on the build/upload/iterate
loop and points at ~/dev/CLAUDE.md for maubot patterns. journal/
README covers the three commands, the SQLite schema, known
quirks (edits don't re-trigger, subcommand detection scope), and
documents why this plugin uses @command.passive instead of the
more obvious @command.new.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`@command.new` silently drops `!journal\n<content>` because
maubot's parser only treats a *space* as the command/args
delimiter — when a newline immediately follows the command
name, the parser fails to recognise the command at all (no
handler invoked, no error). Real users WILL paste:
!journal
- thing one
- thing two
and lose the entry without any feedback.
Switching to `@command.passive` with a regex that admits
[ \t\r\n] as the delimiter catches every form. Subcommand
dispatch (show/today) moves into the handler body — small
loss of decorator ergonomics, big gain in robustness for the
dominant use case (freeform multi-line entries).
Bumped to 0.2.0 since the structural change warrants a minor
bump (not a fix-level patch).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Records what people did each day, scoped per-room/sender/timestamp.
Stored in maubot's per-instance SQLite plugin DB.
Commands:
- !journal <text> record an entry
- !journal show [@u] last 10 entries, optionally filtered by user
- !journal today everything logged today (UTC)
The command shape requires @command.new(arg_fallthrough=False) so
the parent's pass_raw=True `text` argument doesn't swallow
subcommand keywords like "show" and "today" — same pattern the
upstream maubot reminder plugin uses.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>