Commit graph

32 commits

Author SHA1 Message Date
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
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
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
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
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
yushen
680668ffdb feat(workspace): add context field for AI agent background info
Add a `context` text field to workspaces, allowing users to provide
background information and context for AI agents working in the
workspace. Full stack: migration, sqlc queries, Go handler, TS types,
SDK, and settings page UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 15:59:11 +08:00
yushen
3293607bef fix(cli): address code review findings
1. Add Client.SendHeartbeat/Register methods — no more direct postJSON calls
2. Use url.Values for query params to prevent URL injection
3. Unexport helpers (envOrDefault, durationFromEnv, sleepWithContext)
4. CLI resolveWorkspaceID falls back to daemon.json
5. Implement agent stop (PUT /api/agents/{id} with status=offline)
6. Add --output flag to agent get for consistent UX
7. Add server/multica to .gitignore for stray builds
8. Inject version/commit via -ldflags in Makefile build target

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 15:49:32 +08:00
yushen
707b5ac6e7 refactor(cli): unify daemon into multica-cli binary with cobra subcommands
Extract daemon logic from cmd/daemon/ into internal/daemon/ package and
create a new unified CLI entry point at cmd/multica/ using cobra. The CLI
supports `daemon` as a long-running subcommand plus ctrl subcommands for
agent/runtime management, config, status, and version.

Server, migrate, and seed binaries remain unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 15:44:49 +08:00
Jiayuan Zhang
4c6eb81789 Provision default workspaces and harden daemon pairing 2026-03-24 15:19:27 +08:00
yushen
f2228e4f22 refactor(daemon): rename DefaultWorkdir to ReposRoot for clarity
MULTICA_AGENT_WORKDIR → MULTICA_REPOS_ROOT to make it clear this is
the parent directory containing all repos, not a single project workdir.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:36:09 +08:00
Jiayuan Zhang
2c28c4cba2 refactor(dev): share postgres across main and worktrees 2026-03-24 14:27:35 +08:00
yushen
96cfdc2e27 fix(agent): fix data races, add tests, and fix raw protocol detection
- Fix data race on output strings.Builder in codex backend by adding
  mutex and waiting for reader goroutine before reading final output
- Fix data race on onTurnDone by initializing it before reader starts
- Fix bug where notificationProtocol zero value "" never matched
  "unknown", silently dropping all raw v2 notifications from codex
- Add round-robin polling to prevent runtime starvation in poll loop
- Log errors in claude handleControlRequest instead of silently dropping
- Add 35 tests for pkg/agent covering claude parsing, codex JSON-RPC,
  protocol detection, event handling, and helper functions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:21:10 +08:00
yushen
0d9b687d92 fix(agent): address code review feedback
- Replace deprecated strings.Title with manual capitalize
- Fix race: set codexClient.onMessage before starting reader goroutine
- Remove unused msgCh parameter from codexClient.handleLine
- Route agent stderr through logger instead of dumping to os.Stderr
- Use deterministic agent order in ensurePaired (prefer codex)
- Increase message channel buffer from 64 to 256
- Rename test to match function rename (buildPrompt)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:10:08 +08:00
yushen
bb45f17cf9 feat(daemon): unified agent SDK supporting Claude Code and Codex
Add a reusable Go agent package (server/pkg/agent/) that provides a
unified Backend interface for executing prompts via either Claude Code
or Codex. The daemon now auto-detects which CLIs are available at
startup, registers a runtime for each, and routes tasks to the correct
backend based on task.Context.Runtime.Provider.

Key changes:
- server/pkg/agent/agent.go: Backend interface, Message/Result types, factory
- server/pkg/agent/claude.go: Spawns claude CLI with stream-json, parses output
- server/pkg/agent/codex.go: Spawns codex app-server, JSON-RPC 2.0 protocol
- server/cmd/daemon/daemon.go: Multi-runtime registration, round-robin polling,
  provider-based backend selection. Removes old runCodexExec/codexResultSchema.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:05:03 +08:00
Jiayuan Zhang
cdfa63af15 feat(runtime): add local codex daemon pairing 2026-03-24 12:03:14 +08:00
Naiyuan Qing
cc2281416e feat(server): add comment CRUD endpoints and issue filter/update enhancements
- Add UpdateComment and DeleteComment handlers with /api/comments/{commentId} routes
- Add broadcast for comment create/update/delete WebSocket events
- Support status, priority, and assignee_id filters on ListIssues
- Extend UpdateIssue to handle due_date, acceptance_criteria, context_refs, repository
- Properly distinguish "field not sent" vs "field sent as null" in UpdateIssue
- Add corresponding SDK methods and TypeScript types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:15:09 +08:00
Jiayuan Zhang
5a3a72c411 feat(server): add task service layer and daemon REST protocol
- Extract TaskService (server/internal/service/task.go) for task lifecycle:
  enqueue with context snapshot, claim, start, complete, fail, progress
- Add daemon protocol endpoints under /api/daemon/:
  register, heartbeat, claim task, start/progress/complete/fail task
- Task ↔ Issue status sync: running→in_progress, completed→in_review, failed→blocked
- Agent status auto-management: reconcile idle/working based on running tasks
- Enforce max_concurrent_tasks on task claiming (FOR UPDATE SKIP LOCKED)
- Add UpdateIssueStatus query (fixes bug where UpdateIssue nulls assignee)
- Extract shared pgx utils to server/internal/util/ to avoid circular imports
- Migration 003: add context JSONB to agent_task_queue, daemon unique constraint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 18:34:51 +08:00
Jiayuan Zhang
b4303f9bec feat(agent): add agent management UI, skills/tools/triggers, and issue assignment
- Complete agents management page with create dialog, runtime device selector,
  skills/tools/triggers/tasks tabs, and agent detail view
- Add AssigneePicker to issue detail page for assigning to members or agents
- Extend agent types with description, skills, tools, triggers, RuntimeDevice
- Add SDK methods for agent CRUD and task listing
- Add migration 002 for agent config columns (skills, tools, triggers)
- Update seed data with realistic agent configurations
- Use auth context as single source of truth for agents (fixes state sync)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 18:31:25 +08:00
Jiayuan Zhang
81e64e9fce Add workspace management and isolated worktree environments 2026-03-23 18:12:11 +08:00
Jiayuan Zhang
b5b0605e9a chore: add one-click setup/start/stop scripts, migration CLI, and seed tool
- Add idempotent seed tool with duplicate detection for agents/issues/comments
- Add migration CLI supporting up/down with schema_migrations tracking
- Add Makefile targets: make setup (first-time), make start, make stop
- Update .gitignore for test artifacts and compiled binaries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 11:50:33 +08:00
Jiayuan Zhang
6dfc61fa86 test: add comprehensive test suite (Go unit/integration, Vitest, Playwright E2E)
- Add JWT middleware unit tests (8 tests covering all auth edge cases)
- Add WebSocket hub tests (5 tests for client lifecycle and broadcast)
- Add full HTTP integration tests (12 tests through real Chi router with DB)
- Add frontend component tests for login, issues, and issue detail pages
- Add auth context unit tests (9 tests for login/logout/name resolution)
- Add Playwright E2E tests for auth, issues, comments, and navigation
- Configure Vitest with jsdom, React plugin, and path aliases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 11:50:25 +08:00
Jiayuan Zhang
1e61c1974c feat(server): implement full REST API with JWT auth and real-time WebSocket
- Add HTTP handlers for issues, comments, agents, workspaces, inbox, members, and activity
- Implement JWT authentication middleware with Bearer token validation
- Add sqlc queries for all entities (CRUD operations)
- Extract router into reusable NewRouter() for testability
- Expand SDK with full API client methods (CRUD for all resources)
- Add updateWorkspace to SDK, add Member type to shared types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 11:50:03 +08:00
Jiayuan Zhang
d4f5c5b16f
feat: pivot to AI-native task management platform (#232)
Replace the agent framework codebase with a new monorepo structure
for an AI-native Linear-like product where agents are first-class citizens.

New architecture:
- server/ — Go backend (Chi + gorilla/websocket + sqlc)
  - API server with REST routes for issues, agents, inbox, workspaces
  - WebSocket hub for real-time updates
  - Local daemon entry point for agent runtime connection
  - PostgreSQL migration with 13 tables (issue, agent, inbox, etc.)
  - WebSocket protocol types for server<->daemon communication
- apps/web/ — Next.js 16 frontend
  - Dashboard layout with sidebar navigation
  - Route skeleton: inbox, issues, agents, board, settings
- packages/ui/ — Preserved shadcn/ui design system (26+ components)
- packages/types/ — Full API contract types (Issue, Agent, Workspace, Inbox, Events)
- packages/sdk/ — REST ApiClient + WebSocket WSClient
- packages/store/ — Zustand stores (issue, agent, inbox, auth)
- packages/hooks/ — React hooks (useIssues, useAgents, useInbox, useRealtime)
- packages/utils/ — Shared utilities

Removed: apps/cli, apps/desktop, apps/mobile, apps/gateway,
packages/core, skills/, and all agent-framework code.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 17:55:49 +08:00