Commit graph

1581 commits

Author SHA1 Message Date
Jiang Bohan
b8c784dda3 merge: resolve conflicts with main
- Take main's router.go, rich-text-editor.tsx, comment-card.tsx
- Remove deleted daemon_pairing.go
- Keep issue mention card feature
2026-03-31 16:25:20 +08:00
LinYushen
2c76a0b905
Merge pull request #227 from multica-ai/fix/fetch-credentials-include
fix(api): add credentials include for cross-origin cookie storage
2026-03-31 16:22:54 +08:00
yushen
d57b98fc78 fix(api): add credentials include to fetch for cross-origin cookie storage
The API at multica-api.copilothub.ai sets CloudFront signed cookies
with Domain=.copilothub.ai, but fetch() defaults to credentials:
'same-origin'. Since the frontend (multica-app.copilothub.ai) and API
are cross-origin, the browser silently drops Set-Cookie headers without
credentials: 'include'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:22:25 +08:00
Jiang Bohan
e16f1579a9 feat(issues): render issue mentions as rich cards with status icon
- Fix mention markdown serialization: use renderMarkdown (tiptap/markdown 3.x API)
  instead of addStorage.markdown.serialize which was silently ignored
- Add IssueMentionCard component showing status icon + identifier + title
- Update Markdown renderer to use card for mention://issue/ links
2026-03-31 16:19:32 +08:00
Naiyuan Qing
9e06b02cfa
Merge pull request #226 from multica-ai/feature/comment-context-menu
feat(editor): migrate to @tiptap/markdown, TitleEditor, comment UX improvements
2026-03-31 16:19:10 +08:00
Jiang Bohan
e0e52bca64 feat(web): move OK emoji to 2nd position, remove thumbs down 2026-03-31 16:19:03 +08:00
Jiang Bohan
57a5b8b7a4 feat(web): add OK emoji to reaction quick bar 2026-03-31 16:19:02 +08:00
Bohan Jiang
8bbc228469 fix(editor): use correct getMarkdown API for @tiptap/markdown (#219)
The migration from tiptap-markdown to @tiptap/markdown (38e92040)
changed the getMarkdown API location. The old package stored it at
editor.storage.markdown.getMarkdown(), but @tiptap/markdown adds it
directly as editor.getMarkdown(). This caused getEditorMarkdown() to
always return "", preventing description (and any markdown content)
from being saved when creating or editing issues/comments.
2026-03-31 16:19:02 +08:00
Jiayuan
94ddbfb4d9 fix(tests): merge main, renumber migration, fix execenv test assertions
Merge main to pick up 028_task_trigger_comment migration. Renumber
daemon_token migration to 029. Fix execenv tests that expected CLI hints
in issue_context.md after they were moved to CLAUDE.md.
2026-03-31 16:19:02 +08:00
Jiayuan
afdfee78b9 feat(daemon): add authentication for daemon API routes
Issue daemon auth tokens (mdt_) on pairing session claim, bound to
workspace_id + daemon_id with 1-year expiry. Add DaemonAuth middleware
that validates these tokens and falls back to JWT/PAT for backward
compatibility. Apply middleware to all daemon routes except pairing
endpoints.
2026-03-31 16:19:02 +08:00
LinYushen
dc3dec8ebe feat(cli): add multica update command (#218)
* feat(cli): add `multica update` command

Detects whether multica was installed via Homebrew (by resolving the
binary symlink and checking if it lives under a Homebrew prefix).

- Brew installs: runs `brew upgrade multica` automatically.
- Non-brew installs: prints instructions for installing via brew or
  downloading from GitHub releases.
- Checks latest version from the GitHub releases API and skips
  the update if already up to date.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): use fully-qualified tap name in brew upgrade

Use `brew upgrade multica-ai/tap/multica` instead of `brew upgrade multica`
to avoid any potential name collision with core formulae.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:19:02 +08:00
Bohan Jiang
9ceea9c17e fix(editor): use correct getMarkdown API for @tiptap/markdown (#217)
The migration from tiptap-markdown to @tiptap/markdown in 38e92040
broke comment creation. The old package stored getMarkdown() on
editor.storage.markdown, but the official @tiptap/markdown extension
adds it directly to the editor instance (editor.getMarkdown()).

This caused getEditorMarkdown() to always return "", making the
submit button permanently disabled and preventing any comments.

Also fix stale submitting ref in useIssueTimeline dependency array.
2026-03-31 16:19:02 +08:00
Bohan Jiang
02918d8229 perf(web): parallelize auth init and non-blocking dashboard layout (#220)
- Fire getMe() and listWorkspaces() in parallel instead of serially,
  saving one network round-trip (~200ms on cloud)
- Render dashboard sidebar shell immediately once user is authenticated,
  show loading indicator in content area while workspace hydrates

Closes MUL-41
2026-03-31 16:19:02 +08:00
Jiayuan
0eaa6e74a4 fix(daemon): update execenv tests to match current renderIssueContext output
CLI hints like "multica issue get" were moved to CLAUDE.md and are no
longer rendered into issue_context.md. Remove stale assertions.
2026-03-31 16:19:01 +08:00
Jiayuan
d4e121284a feat(inbox): add archive button on individual inbox list items
Show an archive icon on hover for each inbox list item, allowing
users to archive a single message directly from the list without
needing to open the detail panel first.
2026-03-31 16:19:01 +08:00
Jiayuan
fc8969a399 fix(issues): remove duplicate commenter header in collapsible comment
The parent comment's header (avatar, name, time, context menu) is now
the collapsible trigger itself. Only the body, reactions, replies, and
reply input collapse — the header is always visible. This removes the
duplicate author info that appeared when expanded.
2026-03-31 16:19:01 +08:00
Jiayuan
90295d8554 fix(daemon): add CLI hint to issue_context.md
renderIssueContext() now includes a "Quick Start" section with the
`multica issue get` command so agents know how to fetch issue details.
Fixes the TestPrepareDirectoryMode and TestWriteContextFiles failures.
2026-03-31 16:19:01 +08:00
Jiayuan
91c279fd2a feat(issues): make entire comment card collapsible with toggle
Each comment card now has a clickable header with a chevron toggle.
When collapsed, shows author, timestamp, and a content preview.
When expanded, shows the full comment body, replies, and reply input.
2026-03-31 16:19:01 +08:00
Jiayuan
ef4e2d94a0 feat(issues): add collapsible toggle for comment replies
Wrap the replies section in a Collapsible component so users can
collapse/expand replies on a comment thread. The parent comment and
reply input remain always visible. A chevron trigger shows the reply
count (e.g. "3 replies") and rotates on open. Default state is expanded
to preserve existing behavior.
2026-03-31 16:19:00 +08:00
Naiyuan Qing
27987adf37 fix(inbox): use issue_id as selection key instead of inbox item id
- URL param: ?id= → ?issue= (keyed by issue, not notification)
- Multiple notifications for same issue now share selection state
- Archive correctly clears selection when archived item's issue matches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:17:41 +08:00
Naiyuan Qing
bb2dd67941 fix(comments): collapsible header overflow, hover style on toggle
- Add shrink-0 to name/time to prevent wrapping when collapsed
- Content preview: min-w-0 flex-1 truncate for proper ellipsis
- Collapsible trigger: add rounded p-0.5 hover:bg-muted for click affordance

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:15:26 +08:00
Naiyuan Qing
26af15f189 Merge remote-tracking branch 'origin/main' into feature/comment-context-menu 2026-03-31 16:15:16 +08:00
LinYushen
b5674869ed
fix(auth): enforce auth on daemon API routes (#224)
* fix(auth): enforce auth middleware and workspace membership on daemon API routes

Daemon routes were registered without the Auth middleware, meaning the
server accepted unauthenticated requests to register runtimes, claim
tasks, etc. The daemon client already sends a Bearer token — the server
just wasn't validating it.

- Split /api/daemon routes: pairing-session endpoints stay public (used
  before the daemon has a token), all others now require Auth middleware
- Add workspace membership check in DaemonRegister so only workspace
  members can register runtimes
- Update test to include X-User-ID header matching the new auth requirement

Closes MUL-90

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(daemon): remove dead pairing-session feature

The daemon pairing flow was never completed — the daemon authenticates
via CLI config token, not pairing sessions. Remove all related code:

- Delete daemon_pairing.go handler (4 unused handlers)
- Remove pairing routes from router.go (3 public + 1 protected)
- Delete /pair/local page + test from frontend
- Remove DaemonPairingSession types and API client methods
- Add migration 029 to drop daemon_pairing_session table
- Update LOCAL_DEVELOPMENT.md to reflect actual auth flow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:13:58 +08:00
Jiang Bohan
a472a0e8e0 fix(editor): override renderMarkdown/parseMarkdown for mention serialization
The @tiptap/markdown extension discovers serializers via the
renderMarkdown extension field, not addStorage(). The previous
addStorage approach was silently ignored, causing mentions to serialize
as shortcode format [@ id="..." label="..."] instead of markdown links.

Now properly overrides renderMarkdown, parseMarkdown, and
markdownTokenizer to serialize mentions as [@Label](mention://type/id)
which the Markdown renderer can handle as clickable links.
2026-03-31 16:09:31 +08:00
Naiyuan Qing
8fae493f01 merge: resolve conflicts with main (file upload support)
- Merge main's file upload (Image extension, Paperclip, useFileUpload)
- Keep our mention/markdown/TitleEditor changes
- Apply RichTextEditor edit/display to main's Collapsible CommentCard layout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:07:45 +08:00
Naiyuan Qing
98829fad29 fix(comments): replace optimistic updates with loading state
- Remove temp-xxx optimistic inserts from submitComment/submitReply
- Wait for API response, then insert real comment into timeline
- Add Loader2 spinner to comment/reply submit buttons during loading
- Remove hover card from Markdown.tsx (will be handled via NodeView later)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:03:13 +08:00
LinYushen
fe0968d96f
Merge pull request #213 from multica-ai/feature/file-upload-cloudfront
feat(upload): file upload API with S3 + CloudFront signed cookies
2026-03-31 16:00:19 +08:00
yushen
1e22633301 Merge remote-tracking branch 'origin/main' into feature/file-upload-cloudfront
# Conflicts:
#	apps/web/components/common/rich-text-editor.tsx
#	apps/web/features/issues/components/comment-card.tsx
#	apps/web/package.json
#	pnpm-lock.yaml
2026-03-31 15:59:46 +08:00
yushen
9e23fb76fc fix(upload): harden upload flow — sanitize filenames, refresh CF cookies, deduplicate handlers
- Sanitize Content-Disposition filenames to prevent header injection (strip control chars, quotes, semicolons)
- Add CloudFront cookie refresh middleware so cookies are re-issued when expired
- Log errors in groupAttachments instead of silently swallowing them
- Move useFileUpload hook to shared/hooks/ per project architecture conventions
- Add uploadWithToast helper to deduplicate try/catch/toast pattern across 3 components
- Refactor ApiClient.uploadFile to reuse auth headers, 401 handling, and error parsing
- Allow empty MIME types client-side (let server sniff and decide)
- Constrain Image extension max-width in rich-text-editor to prevent layout overflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:52:40 +08:00
Jiang Bohan
c5b0535a3f fix(markdown): allow mention:// protocol through URL sanitization
react-markdown v10's defaultUrlTransform strips URLs with non-standard
protocols (only http/https/irc/mailto/xmpp allowed). This caused
mention://issue/ links to have empty hrefs, breaking click navigation
to issue detail pages.
2026-03-31 15:52:03 +08:00
Naiyuan Qing
b9ea10c89d fix(comments): unify rendering with RichTextEditor, fix mention/link colors
- Comment display: replace <Markdown> with <RichTextEditor editable={false}>
- Link color: primary → brand (blue)
- Mention color: brand → primary + semibold
- Add MentionHoverCard component with HoverCardTrigger render={<span />}
- Markdown.tsx: sync mention style to text-primary font-semibold

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:50:22 +08:00
Jiayuan Zhang
5a7b34cab5
Merge pull request #211 from multica-ai/agent/lambda/5e70a174
fix(agent): fix agent visibility defaults and permission model
2026-03-31 15:50:07 +08:00
Jiayuan
feb5f57662 fix: merge main and renumber migration 028 → 030
Main now has 028 (task_trigger_comment) and 029 (daemon_token).
Renumber agent_default_private migration to 030 to avoid conflict.
2026-03-31 15:47:09 +08:00
Jiayuan
ac17fd33bf Merge remote-tracking branch 'origin/main' into agent/lambda/5e70a174 2026-03-31 15:45:59 +08:00
Jiayuan Zhang
a2ea8197e2
Merge pull request #221 from multica-ai/agent/lambda/bd1d07a6
feat(server): trigger agents via @mention in comments
2026-03-31 15:44:41 +08:00
Jiayuan
7aea32cb33 fix(server): suppress assignee on_comment when mentions target others
When a comment @mentions anyone but not the assignee agent, the
assignee's on_comment trigger is now suppressed. This prevents the
assignee agent from being re-triggered when users share results with
colleagues or ask other agents for help.

The rule: @mention is an intent signal — if you're talking to someone
else, the assignee agent should not respond.
2026-03-31 15:42:54 +08:00
yushen
f5353c6691 feat(upload): signed URLs for CLI + eager load attachments on comments
- Add CloudFrontSigner.SignedURL() for generating per-resource signed URLs
- Attachment responses include download_url (5-min signed URL for CLI)
- Eager load attachments on comments and timeline (same pattern as reactions)
- Add ListAttachmentsByCommentIDs query for batch loading
- Update Comment and TimelineEntry types with attachments field

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:42:10 +08:00
Naiyuan Qing
9f03b73809 feat(editor): add TitleEditor component, replace <input> for issue titles
- New TitleEditor: minimal tiptap (Document+Paragraph+Text+Placeholder)
- Single-paragraph constraint prevents Enter from creating new lines
- contenteditable div enables visual word-wrap (no horizontal scroll)
- Enter→submit+blur, Shift+Enter blocked, Escape→blur
- Replace <Input> in create-issue modal and <input> in issue-detail
- Remove titleDraft state/titleFocusedRef/sync effect from issue-detail
- Fix duplicate React key: TitleEditor key={`title-${id}`}

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:38:42 +08:00
Naiyuan Qing
ac2a4c419f refactor(editor): migrate to @tiptap/markdown, fix mention rendering
- Replace tiptap-markdown with official @tiptap/markdown (markdown→JSON direct, skip DOM)
- Add contentType:"markdown" for proper \n\n paragraph parsing
- Fix mention renderHTML: use mergeAttributes for class/data-type, <a>→<span>
- Fix type attribute leak: add renderHTML:()=>({}) to suppress raw "type" attr
- Link style: permanent underline → hover-only underline (matches read-only)
- Mention style: primary+background pill → brand color text only
- Comment edit: replace <input> with RichTextEditor for consistency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:38:29 +08:00
Jiang Bohan
7df140bcda feat(issues): add @ mention for issues in comments
Support mentioning issues via @ in the rich text editor with fuzzy
search on identifier and title. Issue mentions render as clickable
links that navigate to the issue detail page.
2026-03-31 15:38:24 +08:00
Jiayuan Zhang
7b68dd8dda
Merge pull request #222 from multica-ai/revert/daemon-auth
revert: daemon authentication for API routes (#214)
2026-03-31 15:33:02 +08:00
Jiayuan
35f77de9cc Revert "Merge pull request #214 from multica-ai/agent/lambda/4771d426"
This reverts commit cfd2fdf70f, reversing
changes made to 987984431b.
2026-03-31 15:30:51 +08:00
Jiayuan
37881adbed feat(server): trigger agents via @mention in comments
When a user @mentions an agent in any issue's comment, the system now
enqueues a task for that agent. The agent reads the issue context and
replies to the triggering comment thread.

Changes:
- Add shared util.ParseMentions for mention parsing (used by both
  comment handler and notification listeners)
- Add EnqueueTaskForMention to TaskService for explicit agent targeting
- Add on_mention trigger type support in agent trigger config
- Add HasPendingTaskForIssueAndAgent SQL query for per-agent dedup
- Add enqueueMentionedAgentTasks in CreateComment handler

Safety: prevents self-trigger (agent mentioning itself), dedup with
assignee on_comment trigger, terminal issue status check, and per-agent
pending task dedup.
2026-03-31 15:30:24 +08:00
yushen
15f96468be feat(upload): add attachment table for tracking uploaded files
- Add attachment table with workspace/issue/comment associations
- Upload handler creates attachment record when workspace context exists
- Add GET /api/issues/{id}/attachments and DELETE /api/attachments/{id}
- Frontend passes issueId context during uploads for tracking
- Add Attachment type, listAttachments, deleteAttachment to API client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:29:41 +08:00
Bohan Jiang
c44da53080
Merge pull request #215 from multica-ai/agent/j/92dbd4ba
feat(web): add OK emoji to reaction quick bar
2026-03-31 15:28:31 +08:00
Bohan Jiang
a5a2673642
fix(editor): use correct getMarkdown API for @tiptap/markdown (#219)
The migration from tiptap-markdown to @tiptap/markdown (38e92040)
changed the getMarkdown API location. The old package stored it at
editor.storage.markdown.getMarkdown(), but @tiptap/markdown adds it
directly as editor.getMarkdown(). This caused getEditorMarkdown() to
always return "", preventing description (and any markdown content)
from being saved when creating or editing issues/comments.
2026-03-31 15:28:02 +08:00
Jiang Bohan
518d4449d7 feat(web): move OK emoji to 2nd position, remove thumbs down 2026-03-31 15:27:13 +08:00
Jiayuan Zhang
cfd2fdf70f
Merge pull request #214 from multica-ai/agent/lambda/4771d426
feat(daemon): add authentication for daemon API routes
2026-03-31 15:27:11 +08:00
LinYushen
987984431b
feat(cli): add multica update command (#218)
* feat(cli): add `multica update` command

Detects whether multica was installed via Homebrew (by resolving the
binary symlink and checking if it lives under a Homebrew prefix).

- Brew installs: runs `brew upgrade multica` automatically.
- Non-brew installs: prints instructions for installing via brew or
  downloading from GitHub releases.
- Checks latest version from the GitHub releases API and skips
  the update if already up to date.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): use fully-qualified tap name in brew upgrade

Use `brew upgrade multica-ai/tap/multica` instead of `brew upgrade multica`
to avoid any potential name collision with core formulae.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:24:05 +08:00
Bohan Jiang
d8a8549c8a
fix(editor): use correct getMarkdown API for @tiptap/markdown (#217)
The migration from tiptap-markdown to @tiptap/markdown in 38e92040
broke comment creation. The old package stored getMarkdown() on
editor.storage.markdown, but the official @tiptap/markdown extension
adds it directly to the editor instance (editor.getMarkdown()).

This caused getEditorMarkdown() to always return "", making the
submit button permanently disabled and preventing any comments.

Also fix stale submitting ref in useIssueTimeline dependency array.
2026-03-31 15:23:13 +08:00