Commit Graph

1594 Commits

Author SHA1 Message Date
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
Bohan Jiang
461dad0dd5 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 15:22:58 +08:00
yushen
423aa38888 feat(upload): add file upload UI — avatar, editor paste/drop, attachments
- Add uploadFile method to ApiClient (FormData + 401 handling)
- Add useFileUpload hook with client-side validation
- ActorAvatar renders actual avatar images with fallback to initials
- Account settings: replace URL input with clickable avatar upload
- RichTextEditor: add Image extension, paste/drop/insertFile support
- Markdown renderer: add img component for uploaded images
- CommentInput & ReplyInput: add paperclip button for file attachments
- Issue description: paste/drop file upload support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:17:54 +08:00
Jiayuan
497fce0061 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 15:17:09 +08:00
Jiayuan
9f56f6af81 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 15:17:09 +08:00
Jiayuan Zhang
56b66908a1 Merge pull request #216 from multica-ai/agent/lambda/92e0a175
feat(inbox): support archiving individual messages from list
2026-03-31 15:16:48 +08:00
Jiayuan
1054e218ed 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 15:15:06 +08:00
Jiayuan Zhang
7d9d6793bc Merge pull request #210 from multica-ai/agent/lambda/cbe4d468
feat(issues): add collapsible toggle for comment replies
2026-03-31 15:12:26 +08:00
Jiayuan
9ba12dffd0 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 15:07:41 +08:00
Jiayuan
8395479653 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 15:07:37 +08:00
yushen
978a5af5de fix(upload): remove unnecessary uploads/ key prefix
Single-purpose bucket with randomized hex keys doesn't benefit from
a prefix — no lifecycle policies or access controls scoped to it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:01:33 +08:00
yushen
c27b7bab5e fix(upload): sniff content type, sanitize filename, add key prefix
- Use http.DetectContentType() instead of trusting client-declared MIME type
- Sanitize quotes in filename for Content-Disposition header injection
- Add uploads/ prefix to S3 keys for better organization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:58:52 +08:00
yushen
edf4c00c08 fix(upload): add file type/size validation, Content-Disposition header
- Add content type allowlist (images, PDF, text, video, audio, zip)
- Enforce 10 MB upload limit via http.MaxBytesReader
- Set Content-Disposition on S3 objects for proper download filenames
- Remove unused CloudFrontSigner.Domain() method

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:55:27 +08:00
Jiayuan
06424f9ba6 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 14:53:05 +08:00
Jiang Bohan
26064e43d1 feat(web): add OK emoji to reaction quick bar 2026-03-31 14:52:30 +08:00
Naiyuan Qing
3b6f64ba8e Merge pull request #212 from multica-ai/feature/comment-context-menu
feat(issues): comment context menu & mention popup positioning fix
2026-03-31 14:46:07 +08:00
Naiyuan Qing
38e92040c4 fix(editor): migrate tiptap-markdown import to @tiptap/markdown
Update import path and remove deprecated config options (html,
transformPastedText, transformCopiedText) that don't exist in the
official @tiptap/markdown package.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:44:00 +08:00
Jiayuan
d729f9c5be 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 14:41:44 +08:00
yushen
29a80e057e feat(upload): add file upload API with S3 + CloudFront signed cookies
Add POST /api/upload-file endpoint that uploads files to S3 and returns
CDN URLs protected by CloudFront signed cookies (same pattern as Linear).

Infrastructure:
- Two private S3 buckets (static.multica.ai, static-staging.multica.ai)
- Two CloudFront distributions with OAC and Trusted Key Groups
- ACM wildcard cert in us-east-1, DNS records in Route 53
- RSA signing key stored in AWS Secrets Manager

Backend:
- S3 storage service with CloudFront CDN domain support
- CloudFront signed cookie generation (RSA-SHA1)
- Private key loaded from Secrets Manager (env var fallback for local dev)
- Cookies set on login (VerifyCode) with 72h expiry matching JWT
- Upload handler: multipart form → S3 → CloudFront URL response

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:41:17 +08:00
Jiayuan
f69aa93a75 feat(agents): add Settings tab for editing agent visibility and properties
Adds a Settings tab to the agent detail panel with:
- Name and description editing
- Visibility toggle (workspace/private) matching the create dialog pattern
- Max concurrent tasks configuration
- Runtime info display (read-only)
2026-03-31 14:40:53 +08:00
Naiyuan Qing
b4bbc16521 fix(issues): use floating-ui for mention popup viewport-aware positioning
Replace hardcoded bottom positioning with @floating-ui/dom computePosition
so the @ mention popup flips above the cursor when near the viewport bottom.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:39:48 +08:00
Jiayuan
af94e22cba merge: resolve conflict with main (comment context menu icons) 2026-03-31 14:37:35 +08:00
Jiayuan
bedf4a05c8 fix(agent): fix agent visibility defaults and permission model
- Change DB default for agent visibility from 'workspace' to 'private'
- Fix canManageAgent: workspace agents are now manageable by all members,
  private agents remain restricted to owner/admin
- Add private agent visibility check to BatchAssigneePicker (was missing)
2026-03-31 14:34:04 +08:00
Jiayuan
7dafb5127d 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 14:33:09 +08:00
Naiyuan Qing
8fa4c8f576 Merge pull request #208 from multica-ai/feature/comment-context-menu
feat(issues): add context menu to all comments with copy support
2026-03-31 14:21:35 +08:00
Naiyuan Qing
d70ab81363 feat(issues): add context menu to all comments with copy support
Own comments show Copy/Edit/Delete; others' comments show Copy only.
Also adds icons to menu items for consistency with other dropdown menus.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:15:09 +08:00
LinYushen
961de18c97 feat(agents): reply as thread instead of top-level comment (#205)
* feat(agents): reply as thread instead of top-level comment

When an agent responds to a user comment, the reply is now nested under
the triggering comment (parent_id) instead of appearing as a separate
top-level comment. Also enables on_comment trigger by default for newly
created agents.

- Add trigger_comment_id column to agent_task_queue (migration 028)
- Pass triggering comment ID through EnqueueTaskForIssue → task → createAgentComment
- Include parent_id in WebSocket broadcast for agent comments
- Default agent creation includes both on_assign and on_comment triggers

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

* feat(cli): add --parent flag to comment add for threaded replies

The agent posts comments via the CLI, so the correct fix is giving it a
--parent flag rather than wiring trigger_comment_id through the task
infrastructure. The agent reads the comment list, decides which comment
to reply to, and passes --parent <comment-id>.

- Add --parent flag to `multica issue comment add`
- Update agent runtime instructions to explain --parent usage

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

* feat(daemon): pass trigger_comment_id to agent execution context

The agent now knows which comment triggered its task and gets an explicit
instruction to reply to it using --parent. The trigger_comment_id flows
from the DB through the claim response, daemon Task struct, and into
issue_context.md where the agent sees it.

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

* fix(comments): agent replies to thread root, matching frontend behavior

When the triggering comment is itself a reply (has parent_id), resolve
to the thread root so the agent's reply stays in the same flat thread.
This matches the frontend where all replies share the top-level parent.

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

* feat(cli): show parent_id and full IDs in comment list

The table output now includes a PARENT column and shows full comment IDs
(not truncated) so agents can see thread structure and use --parent.

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

* feat(daemon): instruct agents to always use --output json

Agents now see explicit guidance to use --output json for all read
commands, ensuring they get structured data with full IDs and parent_id
for proper threading.

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

* feat(daemon): differentiate comment-trigger vs assign-trigger context

When triggered by a comment, the agent now gets clear instructions:
- Primary goal is to read and respond to the comment
- Do NOT change issue status just because you replied
- Only change status if explicitly requested

This prevents the agent from seeing "In Review" and stopping, since
it now understands the task is to reply, not to re-evaluate the issue.

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

* fix(daemon): split workflow by trigger type in CLAUDE.md/AGENTS.md

The Workflow section in the agent's runtime config now shows a
comment-reply workflow when triggered by a comment (read comments,
find trigger, reply, don't change status) vs the full assignment
workflow (set in_progress, do work, set in_review).

Previously the agent always saw the assignment workflow, causing it
to check the issue status, see "In Review", and stop without reading
or replying to the triggering comment.

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

* refactor(daemon): remove duplicate workflow from issue_context.md

Workflow instructions now live only in CLAUDE.md/AGENTS.md (runtime_config.go).
issue_context.md keeps just the task data: issue ID, trigger type, and
triggering comment ID.

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

* fix(task): skip duplicate comment on completion for comment-triggered tasks

When triggered by a comment, the agent posts its own reply via CLI
with --parent. The task completion path was also creating a comment
from the agent's stdout output, resulting in duplicates. Now only
assignment-triggered tasks auto-post output as a comment. Error
messages from FailTask are still posted regardless of trigger type.

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 13:48:39 +08:00
Naiyuan Qing
5517136d73 Merge pull request #207 from multica-ai/feature/ws-self-event-filtering
feat(realtime): WS self-event filtering, issue-detail refactor, sync gap fixes
2026-03-31 13:19:39 +08:00
Naiyuan Qing
6761310038 fix(sync): board-card rollback, inbox status sync, markRead error handling
- board-card: capture prev issue before optimistic update, restore on error
- useRealtimeSync: wire issue:updated WS handler to update inbox issue_status
- inbox: markRead uses optimistic update, refetch on error with toast

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:09:17 +08:00
Naiyuan Qing
a2e5cbd47b refactor(issues): extract hooks from issue-detail, eliminate dual source of truth
- Remove useState<Issue> mirror anti-pattern — read directly from useIssueStore
- handleUpdateField now writes to global store (board/list sync instantly)
- handleDelete now calls removeIssue (deleted issue disappears from list)
- Extract useIssueTimeline hook (comment CRUD + WS events + reconnect)
- Extract useIssueReactions hook (issue reactions + WS events)
- Extract useIssueSubscribers hook (subscribers + WS events + rollback)
- Add useWSReconnect hook for per-component reconnect handling
- Add React.memo to BoardCardContent, DraggableBoardCard, ListRow
- Add key={id} to RichTextEditor to fix stale description on issue switch
- issue-detail.tsx: 1330 → 979 lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:09:17 +08:00
Naiyuan Qing
3e8c715de8 feat(realtime): skip WS refetch for self-triggered events
Backend WS messages now include actor_id from the Event struct.
Frontend useRealtimeSync skips the debounced refetch when the event
was triggered by the current user, eliminating unnecessary re-renders
of heavy components (~400ms after each user action).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:09:17 +08:00
Jiayuan Zhang
c1f81427f6 Merge pull request #206 from multica-ai/agent/lambda/6e8277a7
feat(web): add My Issues page with grouped filters
2026-03-31 12:57:02 +08:00
Jiayuan
d199b6c728 feat(web): add My Issues page with grouped filters
Add a new "My Issues" page accessible from the sidebar, positioned
between Inbox and Issues. Issues are grouped into three collapsible
sections: assigned to me, assigned to my agents, and created by me.
2026-03-31 12:53:21 +08:00
Jiayuan Zhang
d183e61653 Merge pull request #204 from multica-ai/agent/lambda/b3857b5a
fix(inbox): skip inbox notification for task:completed events
2026-03-31 12:41:21 +08:00
Jiayuan
43fceb9117 fix(inbox): skip inbox notification for task:completed events
Task completion is already visible from the issue status change,
so a separate inbox notification is unnecessary noise.
2026-03-31 12:26:26 +08:00
Naiyuan Qing
2152fec4ee Merge pull request #203 from multica-ai/forrestchang/issue-filter-assignee-creator
feat(issues): add assignee and creator filters
v0.1.10
2026-03-31 11:06:16 +08:00
Naiyuan Qing
0cc9c213b5 feat(issues): add assignee and creator filters with two-level dropdown
Add Assignee and Creator filter categories to the issue board filter menu,
using DropdownMenu sub-menus with hover-visible checkboxes (shadcn official
data-selected pattern from PR #6862).

Key changes:
- view-store: add assigneeFilters, includeNoAssignee, creatorFilters state
  with positive selection model (empty = no filter, selected = show only matching)
- issues-header: two-level DropdownMenu — category list → sub-menu with
  searchable checkbox items, issue counts, avatar grouping (Members/Agents)
- utils/filter: extract shared filterIssues() to eliminate duplication
  between issues-page and issues-header
- Workspace switch clears actor filters via deferred subscription
  (dynamic import to avoid circular dependency)
- 10 new filter behavior tests covering assignee, creator, no-assignee,
  and combined filter scenarios

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 11:04:21 +08:00
Naiyuan Qing
1abd3ee918 chore(ui): switch shadcn menuColor from inverted-translucent to default
Replace semi-transparent glassmorphism menus with solid popover backgrounds.
Re-downloaded dropdown-menu, context-menu, select, combobox, menubar, and
button via `npx shadcn add --overwrite`. Also removed `focus:**:text-accent-foreground`
from DropdownMenuCheckboxItem to prevent color cascade into nested components.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 11:01:54 +08:00