Commit graph

1433 commits

Author SHA1 Message Date
Jiayuan
63fd7efc95 feat(inbox): hide issue detail sidebar by default
The properties sidebar in the inbox view is not needed by default.
Add defaultSidebarOpen and layoutId props to IssueDetail so inbox
can start with the sidebar collapsed and persist its layout separately.
2026-03-30 02:41:41 +08:00
Jiayuan Zhang
663dec52b8
Merge pull request #173 from multica-ai/forrestchang/fix-cli-login-token
fix(cli): always update server_url on login
2026-03-30 01:51:33 +08:00
Jiayuan
c3a9190016 fix(cli): always update server_url on login
Previously, `multica login` only saved server_url to config when it was
empty. A stale value (e.g. from a prior session pointing at a different
host) was never overwritten, causing subsequent API calls to hit the
wrong server.
2026-03-30 01:49:07 +08:00
Jiayuan Zhang
a10515fa74
Merge pull request #172 from multica-ai/forrestchang/agent-repo-context
feat(daemon): agent-driven repo checkout with bare clone cache
2026-03-29 19:44:27 +08:00
Jiayuan
99ada27925 merge: resolve conflicts with main (workdir reuse)
Main added execenv.Reuse() for workdir reuse across tasks on the same
issue. Our branch removed Type/BranchName/gitRoot from Environment
(repos are now checked out on demand). Resolution: keep Reuse() but
simplify it to work with the new Environment struct (no workspace type
tracking). Keep the "reused" log field from main, drop removed fields.
2026-03-29 19:42:51 +08:00
Jiayuan
cdc1ac708e feat(daemon): agent-driven repo checkout with bare clone cache
Agents now decide which repo to use based on issue context and check out
repos on demand via `multica repo checkout <url>`. Workspace repos are
cached locally as bare clones for fast worktree creation.

Key changes:
- Add repocache package for bare clone management (clone, fetch, worktree)
- Add `multica repo checkout` CLI command that talks to local daemon
- Add POST /repo/checkout endpoint on daemon health server
- Pass workspace repos metadata through register + task claim responses
- Remove pre-created worktrees from execenv (workdir starts empty)
- Update CLAUDE.md template to instruct agents to use `multica repo checkout`
- Pass MULTICA_DAEMON_PORT, WORKSPACE_ID, AGENT_NAME, TASK_ID env vars to agent
2026-03-29 19:37:48 +08:00
Jiayuan Zhang
3b58dff375
Merge pull request #171 from multica-ai/forrestchang/issue-resume-qa
feat(daemon): reuse workdir across tasks on same agent+issue
2026-03-29 18:42:11 +08:00
Jiayuan
ce2b263ea5 feat(daemon): reuse workdir across tasks on same agent+issue pair
Previously each task created a fresh workdir via execenv.Prepare(), even
when resuming work on the same (agent, issue). This caused the agent's
session context to be out of sync with a blank code state.

Now the server returns prior_work_dir in the claim response, and the
daemon tries execenv.Reuse() first — which wraps the existing directory,
detects git worktree state, and refreshes context files. Falls back to
Prepare() if the prior workdir no longer exists. Workdirs are no longer
cleaned up after task completion so they remain available for reuse.
2026-03-29 18:40:29 +08:00
Naiyuan Qing
ab4058b1e4
Merge pull request #170 from multica-ai/NevilleQingNY/ui-polish
fix(ui): restore issue identifier in breadcrumb
2026-03-29 17:59:13 +08:00
Naiyuan Qing
04cba6fc46 fix(ui): restore issue identifier in breadcrumb
Re-add issue.identifier (e.g. MUL-42) to the breadcrumb nav that was
incorrectly removed during merge conflict resolution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:57:12 +08:00
Jiayuan Zhang
5211947104
Merge pull request #168 from multica-ai/forrestchang/agent-arch-review
feat: session persistence, agent instructions, and on_comment trigger
2026-03-29 17:54:22 +08:00
Naiyuan Qing
6b84186fb2
Merge pull request #169 from multica-ai/NevilleQingNY/invite-inbox-realtime
feat: inbox workspace isolation, realtime routing, and UI polish
2026-03-29 17:52:44 +08:00
Jiayuan
b112d1f1ae feat(tasks): add coalescing queue and task lifecycle guards
- Coalescing queue: use HasPendingTaskForIssue (queued/dispatched only)
  instead of HasActiveTaskForIssue so comments during a running task
  enqueue exactly one follow-up task that picks up all new comments.
- Stale task cleanup: runtime sweeper now fails orphaned tasks when
  their runtime goes offline (daemon crash/network partition).
- Cancel-aware daemon: handleTask checks task status after execution
  and discards results if the task was cancelled mid-run (e.g. reassign).
- Terminal issue guard: ClaimTaskForRuntime auto-cancels pending tasks
  for done/cancelled issues instead of executing them.
- Race condition safety net: unique partial index ensures at most one
  pending task per issue at the DB level.
2026-03-29 17:52:35 +08:00
Naiyuan Qing
b0a6489ac6 fix(ui): polish issue detail — wider content, thinner comment border, smaller props text
Increase content max-width to 4xl, use ring-only border on comment
input, and reduce property sidebar value text to text-xs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:51:02 +08:00
Naiyuan Qing
3a8aec7d08 merge: resolve conflict in issue-detail breadcrumb
Keep identifier removed from breadcrumbs per design decision.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:45:53 +08:00
Naiyuan Qing
abe3c5967a fix(ui): switch issue title to inline editable input
Replace the click-to-edit h1/Input toggle with a persistent inline
input that saves on blur/enter. Removes duplicate issue ID from
breadcrumbs. Uses a ref to prevent realtime updates from clobbering
in-progress edits.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:43:12 +08:00
Naiyuan Qing
b6119878ec fix(ui): improve board card hover with shadow and text contrast
Cards now show muted title text by default that becomes full contrast on
hover, paired with a shadow-md elevation effect. Removes the old
opacity-based hover that made cards fade out.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:43:06 +08:00
Naiyuan Qing
afbbf6ff25 feat(settings): redesign members tab with dropdown menu
Replace inline select + delete button with a three-dot dropdown menu
per member. Adds role descriptions, owner self-demotion protection, and
a cleaner list layout with ring border.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:42:59 +08:00
Naiyuan Qing
8d34e079e8 feat(invite): show toast when invited to workspace
member:added event now includes workspace_name. Frontend shows a toast
notification when the current user is invited. Also clears stale member
list on workspace switch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:42:55 +08:00
Naiyuan Qing
4914f1d5dd feat(realtime): route personal events to target user only
Inbox events (new, read, archived, batch) are now sent via SendToUser
instead of broadcasting to the entire workspace room. Adds a new
Hub.SendToUser method. Also guards task broadcasts against deleted
issues to prevent global event leaks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:42:50 +08:00
Naiyuan Qing
4126073229 feat(inbox): scope all inbox queries by workspace_id
Inbox items were previously queried only by recipient, which leaked data
across workspaces. All list/count/batch operations now filter by
workspace_id from the X-Workspace-ID header.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:42:45 +08:00
Jiayuan Zhang
4ceb7c27b0
Merge pull request #167 from multica-ai/forrestchang/runtime-review
refactor(runtimes): split page, add store, time range
2026-03-29 17:06:54 +08:00
Jiayuan
87e76078ce revert(runtimes): remove runtime delete functionality
Remove the full-stack delete feature (SQL query, Go handler, route,
API client method, and UI delete button with confirmation dialog).
2026-03-29 17:05:36 +08:00
Jiayuan
ceba8556f5 refactor(runtimes): split monolithic page, add zustand store, time range selector, and delete support
- Split 1189-line runtimes-page.tsx into focused sub-components (list, detail, ping, usage, 5 chart files, shared UI, utils)
- Add useRuntimeStore zustand store for shared runtime state across pages (agents page now uses it too)
- Add 7d/30d/90d time range selector to usage charts
- Add full-stack runtime delete: SQL query, Go handler, API route, frontend with confirmation dialog
- Remove unused daemon:heartbeat WS listener (server never broadcasts it)
2026-03-29 17:02:25 +08:00
Jiayuan
32f795e1ef feat(agent): trigger agent on member comment (on_comment trigger)
When a member comments on an issue assigned to an agent, automatically
enqueue a new task if the agent has on_comment trigger enabled (or no
triggers configured). Combined with session persistence, the agent
resumes its prior conversation context and sees the new feedback.

- Add HasActiveTaskForIssue query to prevent duplicate task enqueue
- Refactor shouldEnqueueAgentTask into reusable isAgentTriggerEnabled
- Add shouldEnqueueOnComment with active-task and status guards
- Call trigger logic from CreateComment handler
2026-03-29 17:01:19 +08:00
Jiayuan
5b2c61cfab feat(agent): add instructions field for agent persona/identity
Add an `instructions` text field to the agent model, allowing users to
define each agent's role, expertise, and working style. Instructions are
injected into CLAUDE.md as an "Agent Identity" section so the agent
knows who it is on every task execution.

- Migration 021: add instructions column to agent table
- Backend: create/update/get agent handlers support instructions
- ClaimTask response includes instructions for daemon injection
- execenv: inject instructions into CLAUDE.md meta-skill
- Frontend: add Instructions tab to agent detail panel
2026-03-29 17:01:07 +08:00
Jiayuan
ffda18c809 feat(agent): add per-task session persistence for Claude Code resumption
Store the Claude Code session ID and working directory when a task
completes. On the next task for the same (agent, issue) pair, look up
the prior session and pass --resume <session_id> to Claude Code so
the agent retains conversation context across multiple tasks on the
same issue.

Changes:
- Migration 020: add session_id and work_dir columns to agent_task_queue
- CompleteAgentTask stores session_id and work_dir on completion
- GetLastTaskSession query retrieves prior session for (agent, issue)
- ClaimTaskByRuntime handler populates prior_session_id in response
- Daemon passes ResumeSessionID through to Claude backend Execute()
- Claude backend adds --resume flag when ResumeSessionID is set
2026-03-29 16:53:28 +08:00
Jiayuan Zhang
e819898185
Merge pull request #166 from multica-ai/forrestchang/readable-issue-ids
feat(issues): add human-readable issue identifiers (e.g. JIA-1)
2026-03-29 16:51:44 +08:00
Jiayuan
9fbac49f24 feat(issues): add human-readable issue identifiers (e.g. JIA-1)
Add per-workspace auto-incrementing issue numbers with a configurable
prefix, producing identifiers like "JIA-1" instead of truncated UUIDs.

Database:
- Add issue_prefix and issue_counter to workspace table
- Add number column to issue table with UNIQUE(workspace_id, number)
- Backfill existing issues with sequential numbers

Backend:
- Issue creation atomically increments counter in a transaction
- API responses include number and identifier fields
- Support issue lookup by identifier format (KEY-N)
- Workspace prefix auto-generated from name, customizable via API

Frontend:
- Display identifier in list rows and issue detail breadcrumb
- Add issue_prefix to Workspace type, number/identifier to Issue type
2026-03-29 16:49:55 +08:00
Jiayuan Zhang
42f72371bd
Merge pull request #165 from multica-ai/forrestchang/feature-audit
feat(runtimes): add usage charts, activity heatmap, and hourly distribution
2026-03-29 15:46:39 +08:00
Jiayuan
36798b1d76 feat(runtimes): add usage charts, activity heatmap, and hourly distribution
Add comprehensive data visualization to the runtime detail page:
- Daily token usage stacked area chart and daily cost bar chart
- Model distribution donut chart with cost breakdown
- GitHub-style activity heatmap (13 weeks of daily token usage)
- Hourly task distribution bar chart with new backend endpoint
- Responsive 2-column grid layout for charts on wide screens

Backend: new GET /api/runtimes/{runtimeId}/activity endpoint
returning hourly task counts from agent_task_queue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 15:44:10 +08:00
Jiayuan Zhang
c5fed182e3
Merge pull request #163 from multica-ai/forrestchang/test-agent-review
Remove auto-init issue on agent creation
2026-03-29 14:24:14 +08:00
Jiayuan Zhang
6871163b0b
Merge pull request #164 from multica-ai/forrestchang/fix-runtime-status
fix(runtime): add server-side sweeper to detect stale runtimes
2026-03-29 14:24:05 +08:00
Jiayuan
b3bbf92a1d fix(runtime): add server-side sweeper to detect stale runtimes
The only path to marking a runtime offline was the daemon's deregister
call on graceful shutdown. If the daemon crashed, was killed, or lost
network, the status stayed "online" forever. Add a background goroutine
that sweeps every 30s and marks runtimes offline after 45s without a
heartbeat (3 missed intervals).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 14:22:12 +08:00
Jiayuan
01ac0a81a9 refactor(agent): remove auto-init issue on agent creation
The createAgentInitIssue flow created a boilerplate "Initialize environment"
issue every time an agent was created, polluting the issue list with low-value
tasks. Agents naturally learn the project context when executing real work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 14:21:49 +08:00
Naiyuan Qing
586c3bf470
Merge pull request #162 from multica-ai/naiyuan/realtime-sync-refactor
feat(realtime): WS invalidation + refetch pattern
2026-03-29 13:51:22 +08:00
Naiyuan Qing
9236674667 feat(realtime): WS invalidation + refetch pattern, inbox bugfixes, UI polish
Refactor real-time sync from per-event precise mutations to WS-as-invalidation-signal + debounced refetch.

Backend:
- Add SubscribeAll to Event Bus — auto-broadcasts ALL events, eliminates manual 25-item allEvents list
- Add skill event constants to protocol, fix skill handler string literals
- Add title_changed activity tracking

Frontend:
- WSClient: add onAny() method for wildcard event subscription
- useRealtimeSync: rewrite to refreshMap + prefix routing + 100ms debounce
- Precise handlers only for side effects: workspace:deleted, member:removed, member:added (self-check)
- Reconnect now refetches all stores (fixes missing members/skills/workspace refresh)
- Stale-while-revalidate: fetch() only shows loading spinner on initial load, not on refetch
- Remove redundant useWSEvent in agents/page.tsx and skills-page.tsx
- WSClient.disconnect() now clears all handler registrations

Inbox bugfixes:
- Unify sidebar badge count with page count via dedupedItems + unreadCount in store
- Sort by time DESC (removed severity-first ordering)
- Ellipsis on truncated detail labels

UI:
- Status/Priority pickers: replace RadioGroup with MenuItem for auto-close on selection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:49:40 +08:00
Jiayuan Zhang
26318f6afd
Merge pull request #161 from multica-ai/forrestchang/explore-cli-cmds
feat(cli): restructure CLI commands for better UX
2026-03-29 01:49:17 +08:00
Jiayuan
38d595d81d feat(cli): restructure CLI commands for better UX
- Add top-level `multica login` that combines auth + workspace auto-discovery
- Restructure daemon into subcommands: start, stop, status, logs
- Add background daemon mode with PID management
- Add daemon deregistration on shutdown (new API endpoint + SQL query)
- Remove unused commands: runtime list, status, agent get/delete/stop
- Make `config` show config directly instead of requiring `config show`
- Update README to reflect new CLI structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 01:43:45 +08:00
Naiyuan Qing
19810363eb
Merge pull request #160 from multica-ai/naiyuan/activity-log
feat: unified activity timeline, comment replies, and inbox notifications
2026-03-29 00:24:11 +08:00
Naiyuan Qing
e72f5f0801 feat(inbox): add priority/due_date notifications, structured details, and hover card
- Add missing notifications for priority_changed and due_date_changed events
- Publish priority_changed and due_date_changed flags from UpdateIssue handler
- Add details JSONB column to inbox_item (migration 019) for structured change data
- Store from/to values in details for status, priority, assignee, and due_date changes
- Notification titles now use plain issue title; details carry structured context
- Add human-readable label maps (statusLabels, priorityLabels) in notification listeners
- Update inbox handler responses to include details field
- Frontend: InboxDetailLabel renders rich subtitles per notification type
  - Status: "Set status to ● In Progress" with StatusIcon
  - Priority: "Set priority to ◆ High" with PriorityIcon
  - Assigned: "Assigned to Bob" with resolved actor name
  - Due date: "Set due date to Apr 20"
  - Comment: truncated comment body preview
- Frontend: HoverCard on inbox items shows issue title + description context
- Add due_date_changed to InboxItemType and typeLabels
- Add tests for priority_changed and due_date_changed notifications

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 00:22:17 +08:00
Naiyuan Qing
b2ee151306 fix(activity): address code review feedback and improve timeline UX
- Extract shared timeAgo utility, remove duplicates from comment-card and issue-detail
- Remove unused replies prop from CommentCard
- Fix recursive delete to remove all descendant replies, not just direct children
- Improve formatActivity with human-readable status/priority labels and actor names
- Validate parent comment exists and belongs to same issue before creating reply
- Add priority_changed activity recording in activity listeners
- Fix activity SQL query to sort ASC (was DESC, then re-sorted in handler)
- Fix reply-input layout alignment and test submit button selector
- Minor: .gitignore additions, button dark mode aria-expanded fix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 00:21:46 +08:00
Naiyuan Qing
5d2e62ccde fix(comments): fix padding, separate CommentInput from ReplyInput
- Remove Card double padding (Card py-4 + inner px-4 was too much, override with !py-0)
- Use lighter border-border/50 for reply separators inside Card
- Create CommentInput component for bottom "Leave a comment" — no avatar, full
  width editor, submit button in footer row below editor
- ReplyInput stays for in-card "Leave a reply" — has avatar, compact inline layout
- Two different components for two different use cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 23:13:03 +08:00
Naiyuan Qing
0c8738676c refactor(comments): flat thread layout in one Card (Linear-style)
Replace recursive Card-in-Card with flat thread layout:
- One Card per comment thread, parent + all replies flat inside
- Replies separated by border-t, not nested Cards
- CommentRow component handles each individual comment (header + content + edit)
- Three-dot menu shows active state when open (data-[popup-open])
- ReplyInput simplified: avatar + editor + submit button, no extra border container
- Nested replies collected recursively but rendered flat

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:39:02 +08:00
Naiyuan Qing
56c06ec13b refactor(timeline): use avatar for activity entries, remove filter, allow nested replies
- Activity entries now show ActorAvatar instead of a small dot (consistent with comments)
- Remove All/Comments/Activity filter toggle (comments are just a type of activity)
- Remove one-level reply restriction in backend (allow nested threading)
- Remove unused Circle import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:13:23 +08:00
Naiyuan Qing
6cc8f7586a fix(comments): cascade delete replies in DB when parent comment is deleted
Change parent_id FK from ON DELETE SET NULL to ON DELETE CASCADE.
Deleting a parent comment now deletes all its replies at the DB level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:04:35 +08:00
Naiyuan Qing
8a9ae0102d fix(comments): cascade delete replies when parent comment is deleted
When a parent comment is deleted, remove all its replies from the timeline
instead of promoting them to top-level (orphaned replies have no context).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:03:46 +08:00
Naiyuan Qing
ba3c8e1b3f fix(activity): address code review feedback
- Fix activity:created WS payload to match frontend expectations
  (issue_id at top level, entry as TimelineEntry object)
- Promote child comments to top-level when parent is deleted
  (both in handleDeleteComment and WS comment:deleted handler)
- Enforce one-level reply nesting: reject replies to replies with 400

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:02:25 +08:00
Naiyuan Qing
e7fe6ea79b feat(activity): unified activity timeline with comment reply support
Replace the comment-only list with a Linear-style unified timeline that
interleaves field changes and comments chronologically.

Backend:
- activity_listeners.go: records field changes (status, assignee, description,
  task completed/failed) to activity_log table on domain events
- Timeline API: GET /api/issues/{id}/timeline merges activity_log + comments
  sorted by created_at
- Comment reply: parent_id column + handler support for threading

Frontend:
- Unified timeline replaces comment list: activity entries as compact muted
  lines, comments as Card components with reply threading
- Filter toggle (All / Comments / Activity)
- Reply UI: inline editor under comments with Cancel/Reply buttons
- Real-time sync for activity:created + comment events
- 10 new Go tests, all passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 21:53:08 +08:00
Naiyuan Qing
3bb79564ed
Merge pull request #159 from multica-ai/naiyuan/subscriber-notifications
feat(notifications): subscriber-driven notification system
2026-03-28 21:17:42 +08:00