Skip to content

fix: store inline prosemirror JSON in ChatMessage.message (HULY-20) - #46

Merged
IamCoder18 merged 1 commit into
mainfrom
fix/huly-20-markup-content-for-chat-messages
Aug 11, 2026
Merged

fix: store inline prosemirror JSON in ChatMessage.message (HULY-20)#46
IamCoder18 merged 1 commit into
mainfrom
fix/huly-20-markup-content-for-chat-messages

Conversation

@IamCoder18

Copy link
Copy Markdown
Owner

Summary

Closes HULY-20. Replaces the reverted PR #44 with the correct approach.

What was wrong with #44

The previous attempt called uploadMarkup() and stored a MarkupBlobRef string in message. The web UI rendered it as literal text:

6a7a6ab9cf8ebd9ad635956a-message-1786407609202

because ChatMessagePresenter uses plain <MessageViewer>, which does:

$: node = markupToJSON(message)

with no MarkupBlobRef resolution step.

Root cause

ChatMessage.message (and Issue.description, Milestone.description, ActivityMessage.message, etc.) is typed TypeMarkup()Markup = string (inline prosemirror-JSON string). The MarkupBlobRef indirection only applies to TypeCollaborativeDoc (used by Document.content, etc.).

The reason huly issue update --body appeared to work despite the same broken pattern: Issue.description is rendered via <CollaborativeTextEditor>, which DOES resolve MarkupBlobRef through the collaborator service. Chat/DM/thread/activity/approval paths use plain <MessageViewer> which doesn't — so they fall back to rendering the ref string as text.

Fix

Convert HTML → prosemirror JSON locally via the existing htmlToMarkup() helper (used by huly issue create since v1.0.x) and store the resulting prosemirror-JSON string inline in message. No blob upload. No MarkupBlobRef. Matches what the web UI's Tiptap editor does.

Applied to all 10 chat-message write paths:

# CLI command Class
1 huly comment add chunter:class:ChatMessage
2 huly comment update chunter:class:ChatMessage
3 huly activity reply add activity:class:ActivityMessage
4 huly activity reply update activity:class:ActivityMessage
5 huly channel message send chunter:class:ChatMessage
6 huly channel message update chunter:class:ChatMessage
7 huly channel thread add chunter:class:ThreadMessage
8 huly channel thread update chunter:class:ThreadMessage
9 huly dm message send chunter:class:ChatMessage
10 huly approval comment chunter:class:ChatMessage

Verification

Posted via the local build on https://huly.aaravlabs.com (the real server, your workspace):

$ node packages/cli/dist/index.js comment add --issue HULY-20 \
    --body-file /tmp/kilo/huly20-fix2.html
✓ added comment  on HULY-20  (6a7a6d8549a193c4466fe2c8)

The new comment's message field now starts with {"type":"doc","content":[{"type":"heading","attrs":{...},"content":[{"type":"text","text":"Fixed (v2): inline prosemirror JSON, NOT MarkupBlobRef"}]}, ...]} — valid prosemirror JSON that MessageViewer renders directly.

When you view HULY-20 in the web UI, the comment should now render as a proper heading + paragraph + list. (The old broken comment from #44 has been deleted.)

CI: typecheck ✅, tests 43/43 ✅, format ✅, lint ✅.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@IamCoder18, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ef65e2ac-4375-48a3-8fac-004777980750

📥 Commits

Reviewing files that changed from the base of the PR and between 01172ea and f8a8ab8.

📒 Files selected for processing (1)
  • packages/cli/src/resources/channel.ts
📝 Walkthrough

Walkthrough

The CLI now converts HTML message bodies to inline ProseMirror markup before storing activity replies, approval comments, channel messages, thread replies, direct messages, and comments. Comment creation output returns the converted markup.

Changes

Message markup serialization

Layer / File(s) Summary
Resource message write conversion
packages/cli/src/resources/activity.ts, packages/cli/src/resources/approvals.ts, packages/cli/src/resources/channel.ts
Create and update operations convert HTML bodies with htmlToMarkup before persistence. Existing timestamps and other flows remain unchanged.
Comment markup persistence and output
packages/cli/src/resources/comment.ts
Comment creation and updates persist converted markup. Comment creation output returns the converted markup.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: storing inline ProseMirror JSON in ChatMessage.message.
Description check ✅ Passed The description directly explains the HULY-20 fix, affected write paths, root cause, implementation, and verification results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/huly-20-markup-content-for-chat-messages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/resources/channel.ts`:
- Around line 1054-1057: Move the htmlToMarkup conversion in the person-message
flow before the --person --dry-run early return, and update the preview output
to use messageMarkup instead of raw body. Keep the actual send path persisting
the same stored markup.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bbf9452d-34a0-4c62-af54-06a338ed7e9f

📥 Commits

Reviewing files that changed from the base of the PR and between 0107d56 and 01172ea.

📒 Files selected for processing (4)
  • packages/cli/src/resources/activity.ts
  • packages/cli/src/resources/approvals.ts
  • packages/cli/src/resources/channel.ts
  • packages/cli/src/resources/comment.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Kilo Code Review
🔇 Additional comments (4)
packages/cli/src/resources/activity.ts (1)

21-21: LGTM!

Also applies to: 375-379, 416-421

packages/cli/src/resources/approvals.ts (1)

21-21: LGTM!

Also applies to: 301-304

packages/cli/src/resources/channel.ts (1)

9-9: LGTM!

Also applies to: 550-555, 618-621, 747-751, 804-806

packages/cli/src/resources/comment.ts (1)

9-9: LGTM!

Also applies to: 89-97, 107-113, 143-153

Comment thread packages/cli/src/resources/channel.ts Outdated
// HULY-20: DM messages are ChatMessage instances — message is TypeMarkup
// (inline prosemirror JSON). Inline storage, same as channel messages.
const messageMarkup = htmlToMarkup(body)
const data: Record<string, unknown> = { message: messageMarkup }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: sendDmMessage has two dry-run preview paths; the first one (lines 1029-1043, triggered when --person is provided) was not updated alongside the second path.

The first dry-run preview at line 1036 still emits the raw HTML body (message: body,), even though the actual stored value (line 1057) is the converted markup. The second dry-run path (lines 1058-1073) now correctly shows the converted markup via data: { message: messageMarkup }. Before this PR both paths were consistent (both showed raw HTML); the change to the second path makes them inconsistent.

This contradicts the PR description's claim that "dry-run preview now shows the converted prosemirror JSON (which is what would be stored)". A user running huly dm message send --person <x> --dry-run --body "<p>hello</p>" will see raw HTML in the preview, but the actual stored value will be the converted markup. This is misleading for dry-run previews.

Consider either (a) moving the messageMarkup = htmlToMarkup(body) computation above the if (opts.person !== undefined && opts.person !== '') block so both dry-run paths can use it, or (b) updating the first dry-run path's JSON to show message: htmlToMarkup(body) directly.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

The previous review's suggestion (inconsistent dry-run preview between the two --person paths) has been resolved in commit f8a8ab8. htmlToMarkup(body) is now computed once before the --person branch (channel.ts:1023), so both dry-run preview paths emit the same converted markup that would be stored.

Files Reviewed (1 file)
  • packages/cli/src/resources/channel.ts - 0 issues
Previous Review Summary (commit 01172ea)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 01172ea)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/cli/src/resources/channel.ts 1057 sendDmMessage first dry-run preview path (lines 1029-1043, triggered when --person is provided) still emits the raw HTML body at line 1036, inconsistent with the second path (lines 1058-1073) which now shows the converted markup. Preview is misleading.
Files Reviewed (4 files)
  • packages/cli/src/resources/activity.ts - 0 issues
  • packages/cli/src/resources/approvals.ts - 0 issues
  • packages/cli/src/resources/channel.ts - 1 issue
  • packages/cli/src/resources/comment.ts - 0 issues

Fix these issues in Kilo Cloud


Reviewed by minimax-m3 · Input: 20.2K · Output: 2.2K · Cached: 107K

The original attempt (PR #44, reverted in #45) called uploadMarkup and
stored a MarkupBlobRef string in `message`. That rendered as literal
text in the web UI because the front-end's MessageViewer component does:

    $: node = markupToJSON(message)

with no MarkupBlobRef resolution step. ChatMessage.message is typed
`TypeMarkup()` — an inline prosemirror-JSON string (`Markup = string`
in @hcengineering/core), not a MarkupBlobRef.

Why the same pattern appeared to work for Issue.description:
Issue.description is also `TypeMarkup()`, but the web UI renders it
through `<CollaborativeTextEditor>`, which DOES resolve MarkupBlobRef
via the collaborator service. So `huly issue update --body` accidentally
worked. The chat/dm/thread/activity paths render through plain
`MessageViewer` and broke.

Fix:
  * Convert HTML → prosemirror JSON locally via the existing
    `htmlToMarkup()` helper.
  * Store the resulting prosemirror-JSON string inline in `message`
    — no blob upload, no MarkupBlobRef.
  * Same pattern applied to all 10 chat-message write paths:
    comment add/update, channel message send/update, thread reply
    add/update, dm message send, activity reply add/update,
    approval comment.

Removed from the previous PR (no longer relevant):
  * `uploadMarkup` and `generateId` imports — not used anymore.
  * Deferred-upload pattern for dry-run on channel paths — dry-run
    preview now shows the converted prosemirror JSON (which is what
    would be stored). No external IO involved in conversion, so no
    point deferring.
  * `wouldUploadMarkup` notes in dry-run output — n/a, no upload.

Verified on https://huly.aaravlabs.com (real server):
  * Posted via the local build: `node dist/index.js comment add --issue
    HULY-20 --body-file /tmp/kilo/huly20-fix2.html`.
  * message field stores inline prosemirror JSON starting with
    `{"type":"doc","content":[{"type":"heading",...}]}`.
  * Web UI's MessageViewer can render this directly without any
    collaborator lookup.
@IamCoder18
IamCoder18 force-pushed the fix/huly-20-markup-content-for-chat-messages branch from 01172ea to f8a8ab8 Compare August 11, 2026 00:45
@IamCoder18
IamCoder18 merged commit 963eda1 into main Aug 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant