Commit graph

1278 commits

Author SHA1 Message Date
Jiayuan
1988c45fb0 chore: rename super-multica references to multica
The project was previously called "super-multica" but has been renamed
to "multica". Update all remaining references in docker-compose, goreleaser,
README, and local development docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 21:01:39 +08:00
Naiyuan Qing
ade113975d
Merge pull request #255 from multica-ai/NevilleQingNY/ui-ux-fixes
feat(ui): UI/UX polish — layout, sidebar, button fixes
2026-03-25 18:54:29 +08:00
Naiyuan Qing
6535efdd97 feat(ui): UI/UX polish — layout, sidebar, button, theme improvements
- Fix global scrollbar overflow by removing h-svh from html element
- Add h-full overflow-hidden to html/body for proper app-like layout
- Fix default button variant: add shadow-sm and hover:bg-primary/90
- Update sidebar create-issue button to bg-background with shadow
- Add WorkspaceAvatar component and search/new-issue actions to sidebar header
- Improve theme provider with TooltipProvider wrapper
- Polish various page layouts, pickers, modals, and code block styling
- Clean up custom.css unused styles

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:53:14 +08:00
yushen
2d53afe471 fix(release): remove before hook that fails in CI
GoReleaser hooks execute commands directly without a shell, so `cd`
(a shell builtin) fails. The hook is unnecessary since go.mod should
already be tidy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:46:55 +08:00
yushen
a5aedf5dfe fix(test): gracefully skip DB tests when database is unreachable
pgxpool.New is lazy and doesn't connect immediately. Add pool.Ping()
after creation so CI environments without PostgreSQL skip cleanly
instead of failing with os.Exit(1).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:44:36 +08:00
LinYushen
04997b4011
Merge pull request #254 from multica-ai/feat/homebrew-release
feat(release): add GoReleaser config and Homebrew tap support
2026-03-25 17:39:07 +08:00
yushen
3b3d2c48b9 refactor(release): rename multica-cli to multica
Rename the binary and all references from multica-cli to multica for a
cleaner command-line experience.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:34:29 +08:00
yushen
22f1005537 fix(release): add test step, fix checkout version, improve brew formula
- Fix actions/checkout@v6 → v4 (v6 doesn't exist)
- Add Go test step before GoReleaser to prevent shipping broken binaries
- Add license and test block to Homebrew formula

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:32:47 +08:00
yushen
4c4f6c4a60 fix(release): use brews instead of homebrew_casks for CLI formula
homebrew_casks is for macOS .app bundles; brews is the correct
GoReleaser v2 key for CLI binaries. Also read Go version from go.mod
instead of hardcoding it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:26:34 +08:00
Naiyuan Qing
f150b39f1e
Merge pull request #253 from multica-ai/NevilleQingNY/review-fixes-acceptance
feat: event bus, WS isolation, global stores, inbox notifications, board polish
2026-03-25 17:22:15 +08:00
yushen
872d2d10bd fix(release): match Go version to go.mod (1.26)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:21:23 +08:00
Naiyuan Qing
97fa09156d fix(test): register event bus listeners in integration test setup
TestWebSocketIntegration was timing out because registerListeners()
was never called — events published via bus had no listeners, so
WS broadcasts never happened.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:19:58 +08:00
Naiyuan Qing
0a5dd068b1 fix(test): add sleep after WS connect for Hub register timing
The Hub processes client registration asynchronously via a channel.
Without a short delay, the issue creation can fire before the client
is added to the workspace room, so the broadcast has no recipients.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:15:23 +08:00
yushen
2f54665833 feat(release): add GoReleaser config and Homebrew tap support
Enable `brew install multica-cli` via multica-ai/homebrew-tap.
GoReleaser builds cross-platform binaries (macOS/Linux, amd64/arm64)
and auto-updates the Homebrew formula on tagged releases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:15:09 +08:00
Naiyuan Qing
77141cf0a7 fix(test): use correct var name testToken (not testAuthToken)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:06:50 +08:00
Naiyuan Qing
ae6abc2fc2 fix(test): pass JWT token and workspace_id in WS integration test
HandleWebSocket now requires auth — update test to include
token and workspace_id query params in the WebSocket URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:00:59 +08:00
Naiyuan Qing
a5a5febdf6 fix(test): events.NewBus → events.New (correct function name)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:54:18 +08:00
Naiyuan Qing
cd3f4ec95a fix(test): update issues page tests for global store architecture
Tests now mock useIssueStore directly instead of api.listIssues,
matching the new architecture where pages read from global stores
and loading shows skeletons instead of "Loading..." text.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:52:05 +08:00
Naiyuan Qing
fc3dc39b82 fix(test): update tests for event bus + room-based Hub signatures
- integration_test: pass events.Bus to NewRouter
- handler_test: pass events.Bus to handler.New
- hub_test: add mock MembershipChecker, JWT token generation,
  replace hub.clients with totalClients() helper for room-based Hub

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:49:45 +08:00
Naiyuan Qing
06122dfe9e merge: resolve conflicts with main (skills feature)
Merge origin/main which added the skills system (structured skills
with meta skill runtime injection). Resolve 4 conflicts:

- workspace/store.ts: keep both skills state + issue/inbox fetch
- types/index.ts: keep Skill types + our event exports
- handler/agent.go: merge visibility filtering + skills batch loading
- pnpm-lock.yaml: accept main's lockfile with skills deps

Also fix skill.go: migrate h.broadcast → h.publish (event bus)
to match our architecture where all WS events go through the bus.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:43:21 +08:00
Naiyuan Qing
3dcd581c7b chore: add server/server binary to .gitignore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:37:43 +08:00
Naiyuan Qing
b0b4c1c31a chore: remove server binary from tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:37:27 +08:00
Naiyuan Qing
66b1defab7 refactor: migrate stores to features/, remove dead packages, add modals + workspace sync
## Store migration (packages → features)
- Delete `packages/store/` — stores moved into web app's feature modules
- Delete `packages/hooks/` — replaced by feature-level hooks
- `features/issues/store.ts` — useIssueStore (was packages/store/issue-store)
- `features/inbox/store.ts` — useInboxStore (was packages/store/inbox-store)
- `features/workspace/store.ts` — absorbs agent state (was packages/store/agent-store)
- All imports updated from `@multica/store` → `@/features/*/store`

## Global modal system
- `features/modals/store.ts` — useModalStore (zustand)
- `features/modals/registry.tsx` — ModalRegistry renders active modal
- Mounted in app/layout.tsx alongside Toaster
- Create Workspace dialog now works (was broken: DropdownMenu ate click)

## Workspace real-time sync
- useRealtimeSync subscribes to workspace:updated, member:removed
- Member removal → auto-switch to another workspace
- Workspace settings update → sidebar reflects name change
- Workspace switch → parallel fetch issues + inbox + agents

## Bug fixes
- theme-provider: guard event.key for IME composition (isComposing check)
- task.go: publish comment:created + inbox:new events on task complete/fail
- listeners.go: broadcast comment:created, workspace:updated, member events
- events.go: add EventCommentUpdated, EventCommentDeleted constants

## Cleanup
- Remove _features/ tracking files (dev-only, not for main)
- Remove server/server binary from worktree
- Update CLAUDE.md to reflect new architecture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:37:22 +08:00
Jiayuan Zhang
daaee733bf
Merge pull request #252 from multica-ai/forrestchang/skills-gap-analysis
feat: structured skills system with meta skill runtime injection
2026-03-25 15:41:27 +08:00
Jiayuan Zhang
42aef6e13e fix: address review issues in skills system
- Fix authorization bypass in DeleteSkillFile (missing workspace/role check)
- Extract skills page into features/skills/ module (thin route shell)
- Fix skill files disappearing after save (use API return values + merge in refreshSkills)
- Fix silently swallowed DB errors in ListAgents/GetAgent skill queries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 15:37:08 +08:00
Jiayuan Zhang
fb709ff143 fix(test): remove skills column from integration test fixtures
Migration 008 drops agent.skills column, so test fixtures inserting
into the agent table must no longer reference it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 15:27:50 +08:00
Jiayuan Zhang
02df33803a feat: structured skills system with meta skill runtime injection
Replace agent.skills TEXT field with structured skill/skill_file/agent_skill
tables. Skills are workspace-level entities with supporting files, reusable
across agents via many-to-many bindings.

Backend: migration 008, sqlc queries, CRUD handler, agent-skill junction,
structured skill loading in task context snapshot.

Daemon: meta skill injection via runtime-native config (.claude/CLAUDE.md
for Claude, AGENTS.md for Codex) so agents discover .agent_context/ skills
through their native mechanism. Lean prompt without inlined skill content.

Frontend: Skills management page, agent Skills tab picker, SDK methods,
TypeScript types, workspace store integration.

Also removes auto-creation of init issues when creating agents.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 15:17:59 +08:00
Jiayuan Zhang
63df5dccda
Merge pull request #251 from multica-ai/forrestchang/agent-arch-analysis
feat(daemon): per-task isolated execution environments
2026-03-25 12:43:34 +08:00
Jiayuan Zhang
678266ec87 feat(daemon): add per-task isolated execution environments
Introduce the `execenv` package that creates isolated working directories
for each agent task. Supports git worktree mode (code tasks) and plain
directory mode (non-code tasks), with `.agent_context/issue_context.md`
injected into the workdir for Claude Code to discover.

Key changes:
- New `server/internal/daemon/execenv/` package (Prepare/Cleanup)
- `runTask()` now creates isolated env instead of using shared reposRoot
- Prompt updated to reference `.agent_context/` files
- Add `WorkspacesRoot` config (default ~/multica_workspaces)
- Add `KeepEnvAfterTask` config for debugging
- Default agent timeout increased from 20min to 2h
- `CompleteTask` now forwards branch name to server

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 12:41:52 +08:00
Naiyuan Qing
0c52b89e40 fix: code review — WS sync bug, Hub race condition, error feedback
- Fix useRealtimeSync never receiving WSClient (useRef → useState for
  re-render trigger, keeping ref for lazy subscribe callback)
- Fix Hub.Run() global broadcast mutating map under RLock (same
  two-phase collect+cleanup pattern as BroadcastToWorkspace)
- Move visibleStatuses to module-level constant (prevent useCallback
  recreation every render)
- Replace console.error with toast.error for user-facing operations
  in issues page and inbox page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:37:23 +08:00
Naiyuan Qing
759dd741bd refactor(server): extract inbox creation to bus listeners, add agent visibility filtering
- Move all CreateInboxItem calls from handlers to centralized inbox_listeners.go
- Enrich issue:updated payload with change context (assignee_changed, status_changed, prev values)
- Enrich comment:created payload with issue context (assignee info)
- Bus listeners handle: issue assign, unassign, reassign, status change, comment notification
- ListAgents filters private agents: only visible to owner_id or workspace admin
- Zero CreateInboxItem calls remain in handler package

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:24:45 +08:00
Naiyuan Qing
19504a217c chore: update feature tracking — all tasks done
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:16:15 +08:00
Naiyuan Qing
5c583ccb82 polish(ui): inline editing, skeleton loading, toast feedback, empty states
- Issue detail: click-to-edit title (Input) and description (Textarea)
- Issue detail: acceptance criteria and context refs always addable (even when empty)
- Comment: optimistic create with temp ID + opacity, rollback on error
- Comment: timestamp hover tooltip shows full date
- Issues page: skeleton loading state, empty column text, "No matching issues" with clear filters
- Inbox page: skeleton loading state for two-panel layout
- Settings: replace raw textarea with shadcn Textarea, replace inline saved/error text with toast
- Settings: member operations use toast feedback (add/remove/role change)
- Sidebar: workspace create error shows toast instead of silent console.error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:15:06 +08:00
Naiyuan Qing
3f71957608 feat(inbox): notification triggers, unread badge, archive UI, View Issue link
- Add GET /api/inbox/unread-count endpoint
- Comment on assigned issue notifies assignee (type: mentioned)
- Status change notifies creator in addition to assignee
- Reassignment notifies old assignee (Unassigned from: ...)
- Fix SDK return types: markInboxRead/archiveInbox return InboxItem
- Add getUnreadInboxCount() to SDK
- Sidebar shows unread inbox badge from store (real-time via WS)
- Inbox detail: View Issue link + Archive button
- Fix IssueAssigneeType in create issue dialog

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:00:07 +08:00
Naiyuan Qing
0ea9c38071 fix(workspace): permission enforcement, invite auto-create, switch clears stores
- DeleteAgent: require owner/admin role (was member-only check)
- ListAgentTasks: add workspace membership verification (was unauthenticated)
- CreateMember: auto-create user if email not found (enables invite flow)
- Workspace switch: clear issue/inbox/agent stores before hydrating new data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 10:46:53 +08:00
Naiyuan Qing
2c02aa357d fix(issues): board polish — blocked column, drag fix, comment perms, task cleanup
- Add "blocked" to STATUS_ORDER/ALL_STATUSES and board visible columns
- Add min-h-[200px] to droppable columns for reliable empty-column drops
- Fix card click-vs-drag conflict with pointer-events-none on Link
- List view uses STATUS_ORDER from config instead of hardcoded order
- Create Issue dialog: add AssigneePicker for assigning on creation
- Issue detail page syncs from global useIssueStore for real-time updates
- Comment UpdateComment/DeleteComment: add author-or-admin permission check
- DeleteIssue: cancel running agent tasks before deletion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 10:32:25 +08:00
Naiyuan Qing
9127e543d5 feat: add event bus, WS workspace isolation, and global store migration
- Add internal event bus (server/internal/events/) with synchronous
  pub/sub and panic isolation per listener
- Upgrade WebSocket Hub to workspace-scoped rooms with JWT auth
  and membership verification on connect
- Add 10 new WS event types (comment CRUD, inbox read/archive,
  agent create/delete, workspace/member events)
- Refactor all handlers and TaskService to publish events via Bus
  instead of direct Hub.Broadcast calls
- Add WS broadcast listener that routes events to correct workspace
- Frontend: WSClient sends token + workspace_id on connect with
  auto-reconnect refetch
- Frontend: centralized useRealtimeSync hook dispatches all WS
  events to global Zustand stores
- Migrate issues and inbox pages from local useState to global
  useIssueStore/useInboxStore
- Make store addIssue/addItem idempotent to prevent duplicates
- Remove dead packages/hooks/src/use-realtime.ts
- Add feature tracking files for 4 planned features

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 10:08:27 +08:00
yushen
0ce25597d6 docs: update CLAUDE.md for post-merge architecture changes
- Update backend entry points (cmd/multica CLI replaces cmd/daemon + cmd/seed)
- Add Agent SDK, Daemon, and CLI package descriptions
- Remove stale frontend section referencing deleted lib/ files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:45:18 +08:00
Naiyuan Qing
57850934d0
Merge pull request #250 from multica-ai/feature/design-system-alignment
refactor(web): self-contained shadcn UI with design tokens
2026-03-24 18:26:39 +08:00
Jiayuan Zhang
9522cb0516
Merge pull request #249 from multica-ai/forrestchang/remove-issue-git-repo
refactor: remove repository field from issues
2026-03-24 18:24:36 +08:00
Naiyuan Qing
0629eb9d79 fix(web): add missing linkify-it dependency and types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:24:30 +08:00
Naiyuan Qing
bf7ea14092 fix(web): add missing markdown dependencies (react-markdown, rehype-raw, remark-gfm, shiki)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:21:24 +08:00
Naiyuan Qing
66e99136c2 refactor(web): self-contained shadcn UI with base-nova style and design tokens
Migrate all shadcn components into apps/web/components/ui/ so the web app
is fully independent from packages/ui for its UI layer. Update to the
latest shadcn base-nova style. Add missing semantic color variables
(success, warning, info, canvas), font-mono mapping, scrollbar styling,
and wrap Select items in SelectGroup for proper padding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:19:26 +08:00
Jiayuan Zhang
e86768823e refactor: remove repository field from issues
The repository JSONB column on the issue table is unused. This removes
it end-to-end: migration to drop the column, sqlc queries, Go handler/
service/daemon/protocol structs, TypeScript types, and the
RepositoryEditor UI component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 18:12:06 +08:00
LinYushen
e3ea7bd02c
Merge pull request #243 from multica-ai/feature/multi-agent-backend
feat(daemon): unified agent SDK supporting Claude Code and Codex
2026-03-24 17:55:08 +08:00
yushen
0b7de54052 Merge remote-tracking branch 'origin/main' into feature/multi-agent-backend
Resolve conflicts:
- CLAUDE.md: merge feature-based frontend docs from main with comprehensive
  architecture docs from HEAD
- Makefile: merge .PHONY targets from both branches
- settings/page.tsx: keep Context field using main's Label component
- auth-context.test.tsx: accept main's deletion (moved to features/auth/)
- cmd/daemon/daemon.go: accept HEAD's deletion (moved to internal/daemon/)
- daemon/client.go: port requestError type and isWorkspaceNotFoundError from
  main's old daemon into the new internal/daemon package

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:53:24 +08:00
yushen
de0a983674 fix(server): remove debug logging and add error handling from review
- Remove debug log.Printf calls from handler/daemon.go and service/task.go
  that used the global log package instead of structured logging
- Remove unused truncate() helper from service/task.go
- Add error handling for EnqueueTaskForIssue in createAgentInitIssue
- Clean up verbose debug logging in daemon/daemon.go handleTask
- Add shutdown sequence comment to codex.go lifecycle goroutine

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:48:01 +08:00
yushen
a9bf22955d chore(daemon): add debug logging for task lifecycle troubleshooting
Add structured logging at key points in the task completion flow:
- Daemon: log result details before sending to server, log claim cycles
- Handler: log incoming CompleteTask requests
- TaskService: log each step of CompleteTask (DB update, issue status
  sync, comment creation, payload parsing)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:38:06 +08:00
yushen
994242d2db feat(agent): auto-create init issue on agent creation with workspace context
When a new agent is created, automatically create an initialization issue
assigned to it so the agent starts working immediately. The issue
description incorporates the workspace context field, giving the agent
background info to set up its environment (clone repos, etc.).

Also adds workspace context to the task context snapshot for all tasks,
and renders it in the daemon prompt so agents always have workspace
background when executing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:38:00 +08:00
yushen
828b75c76d fix(daemon): resolve codex app-server deadlock after turn completion
The codex backend spawns a long-running app-server process that doesn't
exit after completing a turn. The lifecycle goroutine was waiting on
<-readerDone which blocks on scanner.Scan() until stdout closes — but
stdout never closes because the process stays alive. This caused the
entire poll loop to freeze, preventing any further task processing.

Fix: explicitly close stdin and cancel the context after the turn
completes, which terminates the codex process and unblocks the reader.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:37:52 +08:00