- Preload output as .cjs so Node.js treats it as CJS regardless of
"type": "module" in package.json
- Add electron-vite dev server ports (5173, 5174) to default CORS origins
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- globals.css: use relative path for @multica/ui/styles/tokens.css
since Tailwind v4's @import resolver doesn't follow pnpm workspace
symlinks + package.json#exports
- globals.css: widen @source globs from *.tsx to *.{ts,tsx} so
Tailwind scans .ts config files — fixes bg-info being purged
(Done badge invisible in light mode)
- layout.tsx: hoist WorkspaceIdProvider above SidebarProvider so
AppSidebar (which now calls useWorkspaceId via useMyRuntimesNeedUpdate
from #533) doesn't throw on mount
- Preload must be CJS (Electron loads it via require), force format: "cjs"
and entryFileNames: "[name].js" so output matches main's reference
- @source paths were 4 levels up but need 5 (src/renderer/src/ to root)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Electron renderer IS a browser — localStorage works natively, no need
for electron-store in preload. Removes the preload module loading issue
and eliminates an unnecessary dependency + IPC bridge.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AuthInitializer was inside DashboardShell which has an isLoading early
return — the initializer never rendered, so isLoading never became false.
Moved to App.tsx (same as web's root layout) so it always executes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bare cache used a mirror-style fetch refspec
(+refs/heads/*:refs/heads/*) which collided with worktree-locked
refs/heads/agent/<task> branches once those branches were pushed
back to origin as PRs. git fetch aborted with "refusing to fetch
into branch ... checked out at ...", the error was swallowed as a
warning, and every subsequent checkout reused the snapshot from
the original clone.
Fix:
- Clone / migrate bare caches to a remote-tracking layout
(+refs/heads/*:refs/remotes/origin/*) so fetched heads never
land in refs/heads/*.
- Resolve the base ref from refs/remotes/origin/HEAD with a
5-level fallback (verified origin/HEAD symref to origin/main
or origin/master to the bare HEAD bridged into origin/<same>
to single-entry origin/* scan to bare HEAD for legacy caches).
- Refuse to guess when refs/remotes/origin/* has multiple
candidates and none match a known fallback, so CreateWorktree
fails loudly instead of basing work on an arbitrary branch.
- Refresh refs/remotes/origin/HEAD after every successful fetch,
not just on the legacy migration path, so a cache that was
already modern picks up an upstream default-branch change.
- Verify the primary symref target actually exists so a phantom
refs/remotes/origin/HEAD from a broken set-head does not
surface a deleted branch.
- Detect legacy caches on the fly and rewrite refspec +
refs/remotes/origin/* + refs/remotes/origin/HEAD in place so
existing clones self-heal on next use.
- Serialize per-bare-repo mutation (both Sync and CreateWorktree)
with sync.Map-backed mutexes so concurrent fetch and worktree
add on the same repo cannot race on git's own lockfiles.
- Narrow the already-exists retry to actual branch-collision
errors so a path-collision no longer silently leaks a branch
into the bare repo.
- multica-icon: copied from web, zero platform-specific deps
- theme-provider: next-themes + TooltipProvider wrapper
- title-bar: draggable frameless title bar with macOS traffic light inset
- app-sidebar: adapted from web — uses @multica/views/navigation instead of next/link
- dashboard-shell: root layout with auth guard, sidebar, outlet, and workspace provider
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace cluttered inline owner pills with a clean two-part filter bar:
- Left: Mine/All segmented control with proper bg-muted container
- Right: Owner DropdownMenu (only in All mode) with avatars and counts
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
List view only showed the first 50 done issues without a total count or
load-more mechanism. Reuse the existing useLoadMoreDoneIssues hook and
extract InfiniteScrollSentinel into a shared component so both board and
list views paginate identically.
* feat(runtime): proactive CLI update notifications with per-user filtering
- Add latestCliVersionOptions query (GitHub Releases API, 10-min TanStack cache)
- Add useMyRuntimesNeedUpdate / useUpdatableRuntimeIds hooks using owner_id
- Show red dot on sidebar Runtimes item when user's runtimes need updates
- Show update arrow icon alongside status dot in runtime list items
* fix(core): add runtimes/hooks to package.json exports
Implement the Master Agent chat feature allowing users to chat with agents
directly from a floating window, separate from the issue-based workflow.
Backend:
- New chat_session and chat_message tables (migration 033)
- Make issue_id nullable on agent_task_queue for chat tasks
- REST API: create/list/get/archive sessions, send/list messages
- EnqueueChatTask in TaskService with session_id persistence
- WS events: chat:message, chat:done
- Daemon: chat task type with separate prompt builder
- ClaimTaskByRuntime populates chat context (session, message, repos)
Frontend:
- ChatSession/ChatMessage types + API client methods
- core/chat: TanStack Query options, mutations with optimistic updates, WS updaters
- features/chat: Zustand store, ChatFab (floating button), ChatWindow with
real-time streaming via task:message events
- Mounted in dashboard layout (bottom-right corner)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show owner avatar + name in runtime list items (replaces text-only)
- Show owner avatar + name in runtime detail info grid
- Add per-owner filter pills in "All" mode for quick filtering
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codex doesn't expose token usage through its JSON-RPC app-server
protocol. The turn/completed and task_complete notifications don't
contain usage fields.
Fix: after Codex execution finishes, scan the on-disk session JSONL
files (~/.codex/sessions/YYYY/MM/DD/*.jsonl) for token_count events.
Only files modified after the task's start time are scanned, avoiding
counting unrelated sessions. This matches the same data format the
existing runtime_usage scanner reads.
CI uses pgvector/pgvector:pg17 which doesn't ship pg_bigm. Wrap
CREATE EXTENSION and index creation in DO/EXCEPTION blocks so the
migration succeeds without pg_bigm — indexes are skipped and search
falls back to plain LIKE scans.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add owner_id to agent_runtime table to track who registered each runtime.
Backend: new delete endpoint with role-based permissions (owner/admin can
delete any, members only their own), list filtering by owner (?owner=me),
and agent dependency check before deletion.
Frontend: Mine/All filter toggle in runtime list, owner display in list
items and detail view, delete button with AlertDialog confirmation.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
P0: Replace all localStorage calls in packages/core with StorageAdapter
- Create StorageAdapter interface (getItem/setItem/removeItem)
- Auth store factory now requires storage parameter
- Workspace store factory accepts optional storage parameter
- WSProvider accepts storage prop for token retrieval
- apps/web/platform/ passes localStorage as the web implementation
P1: Remove sonner UI dependency from packages/core
- Replace toast.error() in workspace store with onError callback
- Move sonner import to apps/web/platform/workspace.ts
- Remove sonner from packages/core/package.json dependencies
P2: Delete 5 pure re-export barrel files in apps/web/features/
- features/issues/index.ts, modals/index.ts, navigation/index.ts,
workspace/index.ts, inbox/index.ts — all had zero consumers
- features/ now only contains auth/ (web-only cookie + initializer)
and landing/ (web-only pages)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(search): implement full-text search for issues
Add pg_bigm-based full-text search across issue titles and descriptions,
with API endpoint, CLI subcommand, and web Cmd+K search dialog.
- Migration 032: pg_bigm extension + GIN indexes on title/description
- Server: GET /api/issues/search?q=... with pagination and total count
- CLI: `multica issue search <query>` with table/json output
- Web: Cmd+K command palette using cmdk, with debounced search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(search): address review feedback on search implementation
1. Escape LIKE special characters (%, _, \) in handler to prevent
matching anomalies from user input.
2. Wire AbortController signal into searchIssues fetch so in-flight
requests are actually cancelled on new input.
3. Fix offset=0 falsy check — use !== undefined instead of truthiness.
4. Merge results + count into single query using COUNT(*) OVER()
window function, eliminating the duplicate DB round-trip.
5. Exclude done/cancelled issues by default; add include_closed
parameter to API, CLI (--include-closed), and web client.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(search): default web search to include all statuses
Pass include_closed: true in the web Cmd+K search so results include
done and cancelled issues by default, matching the reviewer's request.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(search): add comment search with snippet extraction
Extend search to cover issue comments in addition to title/description.
Results are deduplicated at the issue level, with match_source and
matched_snippet fields indicating where and what matched.
- Migration 033: pg_bigm GIN index on comment.content
- SQL: EXISTS subquery for comment matching, correlated subquery for
snippet extraction, 3-tier ranking (title > description > comment)
- Server: SearchIssueResponse with match_source and matched_snippet
- Web: show comment icon + snippet below issue title when matched
- CLI: MATCH column shows source and truncated snippet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(search): redesign search dialog to match Linear's spacious style
- Widen dialog from sm (384px) to xl (576px) with top-20% positioning
- Larger search input with icon, generous padding, and ESC hint
- Use cmdk primitives directly for full style control
- Taller result list (400px / 50vh), spacious result items (py-2.5)
- Rounded-lg items with accent highlight on selection
- Cleaner border separator between input and results
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(web): multi-agent sticky card with expand/collapse pattern
- Move sticky positioning to the wrapper div so the entire agent area
sticks together instead of each card independently
- Show first agent card always visible, with "N more agents working"
expand button for additional agents
- Remove scrollContainerRef prop (no longer needed with native sticky)
- Simplify SingleAgentLiveCard by removing auto-collapse-on-scroll logic
* fix(web): pin primary agent card to top and drop collapse UI
- Remove the mt-4 wrapper around AgentLiveCard in issue-detail so the
sticky wrapper is a direct child of the Activity section — sticky now
has a tall enough parent to stay pinned through TaskRunHistory and
the full comment timeline
- Simplify multi-agent rendering: only the first running agent sticks
to the top, any additional agents render below it and scroll with
the page. Removes the expand/collapse "N more agents working" button
- Update subtitle: "The open-source managed agents platform"
- Add managed agents positioning to "What is Multica?" section
- Add lifecycle summary line above Features list
- Mirror all changes in Chinese README
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(issues): add fullscreen agent execution transcript view
Adds a new "expand" button (Maximize2 icon) to both the live agent card
and execution history entries. Clicking it opens a fullscreen dialog with:
- A colored timeline progress bar showing execution flow at a glance
(green = agent text, violet = thinking, blue = tool calls,
gray = results, red = errors)
- Detailed event list with type labels, summaries, and expandable detail
- Click-to-scroll: clicking a timeline segment scrolls to that event
- Copy-all button for the full transcript
Inspired by Anthropic's Cloud Managed Agents session transcript UI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(issues): add runtime and agent metadata to transcript dialog
Adds metadata chips to the transcript dialog header showing:
- Runtime provider (e.g., "Claude Code", "Codex")
- Runtime environment name + mode (local/cloud)
- Agent description
- Duration, tool count, event count, and creation time
Metadata is fetched on dialog open via existing API endpoints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace "multi-tenant environment" restriction with "hosted or embedded
service" restriction. Internal use with multiple workspaces is now
explicitly allowed. Only providing Multica as a hosted service to third
parties or embedding it in a commercial product requires a license.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace standard Apache 2.0 with a modified version that adds:
- Multi-tenant SaaS restriction (requires commercial license)
- Frontend LOGO/copyright protection
- Contributor agreement for relicensing rights
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the sub-issues section only rendered when child issues were
present. This adds a Linear-style "+ Add sub-issues" button below the
description area so users can create sub-issues from an empty state.
- Add Linear-style "Sub-issue of …" breadcrumb under the title with a
parent progress ring
- Refresh sub-issues section: progress ring badge, identifier column,
bordered list, collapse toggle, dashed assignee placeholder
- useUpdateIssue + onIssueUpdated WS handler now also patch and
invalidate the parent's children query so sub-issue status/assignee
changes show up on the parent page without a refresh