Commit graph

1525 commits

Author SHA1 Message Date
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
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
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
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
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
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
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
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
Jiayuan Zhang
b9fdaf62ac
Merge pull request #202 from multica-ai/forrestchang/issue-status-style
feat(ui): restyle issue status and priority with colored badges
2026-03-31 03:28:25 +08:00
Jiayuan
8a61c94b98 feat(ui): restyle issue status and priority with colored badges
- Status labels use colored pill badges (solid bg for active, muted for inactive)
- Board columns have tinted backgrounds matching their status color
- Priority badges use orange (--priority) design token for clear distinction from status
- Issue cards restructured: identifier, title, then assignee/priority/date row
- Agent avatar default color changed from blue to gray
- New Issue button in header changed to solid/primary style
- Reduced hover shadow on board cards
- Added inheritColor prop to StatusIcon and PriorityIcon for badge use
2026-03-31 03:26:43 +08:00
Jiayuan Zhang
32e19f847f
Merge pull request #201 from multica-ai/forrestchang/agent-live-output
feat(agent): stream live agent output and execution history
2026-03-30 23:51:07 +08:00
Jiayuan
a00485cf13 feat(security): redact sensitive information in agent live output
Server-side (primary): Apply redact.Text/InputMap on task message
content, output, and input fields before DB persistence and WebSocket
broadcast. Extended redact package with GitLab tokens, JWTs, connection
strings, and PASSWORD/SECRET/TOKEN env var patterns.

Frontend (fallback): redactSecrets utility mirrors server patterns,
applied in buildTimeline and ToolCallRow render as a safety net.
2026-03-30 23:38:49 +08:00
Jiayuan
e20e1b74dc merge: resolve conflicts with main (reactions feature)
Main added reaction routes and event types while this branch added
task message routes and event types. Both sides kept — no code lost.
2026-03-30 23:29:42 +08:00
Jiayuan
83f325c586 fix(ui): apply mono font directly to code/pre elements
Browser UA stylesheet sets font-family: monospace on <code> and <pre>,
overriding the inherited Geist Mono from parent containers. Apply
font-mono explicitly on these elements so they use the project's
monospace font instead of the browser default.
2026-03-30 23:27:09 +08:00
Jiayuan
1e2052c689 feat(agent): improve live output UI and add execution history
- Fix duplicate icons in tool call rows (use chevron only for expand/collapse)
- Show detailed tool information (WebSearch queries, Agent prompts, Skill names)
- Add thinking/reasoning rows with Brain icon and expandable content
- Show tool results as separate chronological entries with previews
- Add TaskRunHistory component for viewing past agent execution logs
- Add listTasksByIssue API endpoint and task-runs route
- Support thinking content blocks in agent SDK (MessageThinking type)
- Improve callID→toolName mapping in daemon message forwarding
2026-03-30 23:10:54 +08:00
Jiayuan
3c93ebaf1c feat(agent): stream live agent output to issue detail page
When an agent is working on an issue, users can now see real-time output
in the issue detail page instead of waiting for completion.

Backend:
- Add task_message table and migration for persisting agent messages
- Add POST /api/daemon/tasks/{id}/messages endpoint for daemon to report
  structured messages (tool_use, tool_result, text, error) in batches
- Add GET /api/daemon/tasks/{id}/messages for catch-up after reconnect
- Add GET /api/issues/{id}/active-task to check for running tasks
- Broadcast task:message events via WebSocket
- Daemon forwards agent session messages with 500ms text throttling

Frontend:
- Add AgentLiveCard component showing live tool calls, text output,
  and progress indicators with auto-scroll
- Wire into issue detail timeline with WS subscription and HTTP catch-up
- Card appears when agent is working, disappears on completion/failure
2026-03-30 22:53:28 +08:00
Jiayuan Zhang
a526b96b6c
Merge pull request #200 from multica-ai/forrestchang/comment-reactions
feat(reactions): emoji reactions for comments and issues
2026-03-30 22:40:54 +08:00
Jiayuan
7c1aabbe3a feat(reactions): add emoji reactions for comments and issue descriptions
Add Slack-style emoji reactions to comments and issue descriptions with
full-stack support: database tables, REST API endpoints, real-time
WebSocket sync, optimistic UI updates, and inbox notifications.

- New `comment_reaction` and `issue_reaction` tables with migrations
- POST/DELETE endpoints for adding/removing reactions on both comments
  and issue descriptions
- Real-time WS events (reaction:added/removed, issue_reaction:added/removed)
- Shared ReactionBar component with quick emoji picker and full emoji-mart
  picker (lazy-loaded)
- Optimistic add/remove with rollback on failure
- Inbox notifications for comment author and issue creator when reacted to
- Reactions included in timeline, comment list, and issue detail responses
2026-03-30 22:37:59 +08:00
Jiayuan Zhang
e07b121fa8
Merge pull request #198 from multica-ai/forrestchang/agent-sandbox-security
feat(security): agent output redaction and private agent visibility
2026-03-30 22:30:27 +08:00
Jiayuan
ad697e0029 feat(security): restrict agent management to owner for private agents
Replace blanket owner/admin role check in UpdateAgent and DeleteAgent
with canManageAgent, which requires the requesting user to be the
agent's owner (or a workspace owner/admin) for private agents.
2026-03-30 22:27:19 +08:00
Jiayuan
0491350f1b feat(security): add agent output redaction and private agent assignment enforcement
- Add redact package to detect and mask secrets (AWS keys, private keys,
  API tokens, bearer tokens, credentials, home paths) in agent output
  before posting as comments in TaskService
- Enforce agent visibility on issue assignment: private agents can only
  be assigned by their owner or workspace admins
- Add visibility picker (workspace/private) to CreateAgentDialog,
  default to private
- Grey out unassignable private agents in the assignee picker with
  lock icon indicator
2026-03-30 22:22:04 +08:00
Jiayuan Zhang
72e3ccfe33
Merge pull request #197 from multica-ai/forrestchang/daemon-profile
feat(daemon): add --profile flag for multi-environment isolation
2026-03-30 20:24:03 +08:00
Jiayuan
8fa1b163a6 feat(daemon): add --profile flag for multi-environment isolation
Allow running multiple daemon instances against different servers (e.g.
production and local dev) simultaneously. Each profile gets isolated
config, PID file, log file, health port, and workspaces root.

Usage:
  multica login --profile dev --server-url http://localhost:8080
  multica daemon start --profile dev

Default profile (no --profile flag) behavior is unchanged.

Closes MUL-42
2026-03-30 20:21:23 +08:00
Jiayuan Zhang
564eb55f90
Merge pull request #196 from multica-ai/forrestchang/task-workspace-dir
feat(daemon): group task directories by workspace ID
2026-03-30 20:15:34 +08:00
Jiayuan
7d126cc549 feat(daemon): group task directories by workspace ID
Task execution environments were all created flat under WorkspacesRoot,
mixing tasks from different workspaces. Now tasks are nested under their
workspace ID for clearer organization and easier per-workspace cleanup.
2026-03-30 20:13:30 +08:00
Jiayuan Zhang
9c3ff52363
Merge pull request #194 from multica-ai/fix/daemon-auto-discover-new-workspaces
fix(daemon): auto-discover new workspaces without restart
2026-03-30 19:34:04 +08:00
Jiayuan
219b174819 fix(daemon): sync workspaces immediately on startup
Run syncWorkspacesFromAPI once before entering the periodic ticker
loop so newly created workspaces are discovered without the initial
30-second delay.
2026-03-30 19:32:24 +08:00