* feat: add online status indicator dot on agent & member avatars
Backend:
- Track member presence via WebSocket connections in the Hub
- Broadcast member:online/offline events when users connect/disconnect
- Add GET /api/workspaces/{id}/members/online endpoint
- Add member:online and member:offline event type constants
Frontend:
- Add isOnline prop to ActorAvatar with a status dot at top-right corner
- Green dot = online, gray dot = offline, no dot = status unknown
- Fetch online member list via new query, update optimistically on WS events
- Derive agent online status from existing agent.status field
- Wire online status through ActorAvatar views wrapper (enabled by default)
* fix: address code review — fix hub tests and avatar rounding
1. Hub tests: consume the member:online presence event from the first
connection before asserting on broadcast messages.
2. ActorAvatar: use rounded-[inherit] on the inner wrapper so callers
can override rounding (e.g. rounded-lg for agent list items).
* fix: consume member:online presence event in integration test
Same fix as the hub unit tests — read and discard the member:online
event before asserting on issue:created in TestWebSocketIntegration.
* fix: sanitize markdown rendering in comments and shared renderers
Add rehype-sanitize to both ReadonlyContent and Markdown components so
that raw HTML parsed by rehype-raw is sanitized against a strict
allowlist before reaching the DOM. On the backend, add a bluemonday
sanitization pass when creating and updating comments to strip
dangerous tags as defense-in-depth.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add mention:// protocol to sanitize allowlist and validate file card URLs
- Add mention:// to rehype-sanitize protocols.href in both ReadonlyContent
and Markdown so @mention links survive sanitization
- Validate data-href on file cards to only allow http(s) URLs, blocking
javascript: and data: schemes in both frontend click handler and backend
bluemonday policy
- Narrow class attribute allowlist to specific elements (code, div, span, pre)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add components.json to packages/ui so shadcn components can be installed
directly into the shared UI package instead of going through apps/web.
Add a root pnpm ui:add script as the canonical install command.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add @multica/eslint-config package (base, react, next configs)
- Replace `next lint` (removed in Next.js 16) with `eslint .`
- Add lint scripts to all packages and desktop app
- Add noUnusedLocals, noUnusedParameters, noImplicitReturns to base tsconfig
- Fix all resulting TS/ESLint errors (unused imports, missing returns,
stale eslint-disable comments from legacy eslint-config-next)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract MulticaIcon and ThemeProvider to packages/ui (remove duplication)
- Extract shared CSS (scrollbar, shiki, entrance-spin) to packages/ui/styles/base.css
- Add NavigationAdapter.openInNewTab/getShareableUrl for platform-agnostic navigation
- Fix window.open() / window.location.href in shared views to use NavigationAdapter
- Add resolve.dedupe for React in electron-vite config
- Fix desktop tsconfig (noImplicitAny: true)
- Use catalog: for all desktop dependencies
- Add shadcn + tw-animate-css to desktop dependencies (fix phantom deps)
- Add typecheck scripts to all shared packages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete packages/ui and packages/utils (zero imports from apps/web),
remove Turborepo, inline tsconfig.base.json into web's tsconfig,
and simplify root scripts to use pnpm --filter directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add drag-to-resize sidebar with localStorage persistence
- Rewrite issue detail page with Tiptap rich text editor, due date picker, acceptance criteria
- Redesign create-issue modal with pill-based property toolbar and expand/collapse
- Consolidate @multica/sdk and @multica/types into apps/web/shared/
- Simplify auth: remove verification codes, PATs, email service (dev-only login)
- Add 401 unauthorized handler to redirect expired sessions to login
- Fix due date format to send full RFC3339 timestamps
- Increase description editor debounce to 1500ms
- Remove arbitrary Tailwind values in create-issue modal
- Renumber migrations (inbox_actor 012→009), remove unused migrations
- UI polish across agents, settings, inbox, knowledge-base pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
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>
- Add success/warning/info semantic design tokens to globals.css
- Replace all raw HTML elements (input, select, textarea, button, label)
with shadcn components (Input, Select, Textarea, Button, Label, Dialog)
across settings, issues, agents, inbox, knowledge-base, and pair pages
- Replace all hardcoded Tailwind colors with design tokens
(text-red-500 → text-destructive, text-green-600 → text-success, etc.)
- Extract shared ActorAvatar component to packages/ui/components/common
- Update status and priority configs to use semantic tokens
- Update CLAUDE.md with component organization guidelines
- Fix login page tests to use label-based queries
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add canvas background color for the base layer
- Sidebar blends into canvas, no border separator
- Content area rendered as floating white panel with rounded corners
and shadow, offset from edges to reveal canvas underneath
- Simplify sidebar nav to: Inbox, Agents, Issues, Knowledge Base
- Add workspace switcher header with MulticaIcon
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These packages are imported in globals.css but were not listed in
package.json, causing CSS build failures on fresh installs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The text wrapper div was rendering when `isStreaming` was true but
`text` was empty, causing a brief empty flex container to appear
between tool executions. Changed condition from `(text || isStreaming)`
to `text` only, so the div only renders when there's actual content.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Delete sessions-spawn.ts, sessions-list.ts and their tests. Update CLI
to remove waitForSubagents polling workaround (delegate is synchronous).
Update UI, desktop IPC, SWE-bench, and system prompt tests to use the
new delegate tool name.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move LoadingIndicator from ChatView into MessageList for consistent padding
- Add isLoading and hasPendingApprovals props to MessageList
- Adjust message spacing (my-1 → my-2) for better visual balance
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create LoadingIndicator component with "generating" and "streaming" variants
- Remove inline loading indicator from StreamingMarkdown (empty content returns empty fragment)
- Use unified LoadingIndicator in ChatView with consistent positioning
- Eliminates layout shift between different loading states
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use container utility class consistently across chat components
- Change container max-width from 5xl to 4xl for better readability
- Adjust message bubble padding (p-3 -> p-2)
- Fix logout dropdown alignment and add destructive variant
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use TipTap's getText({ blockSeparator: '\n' }) instead of doc.textContent
to preserve newlines between paragraphs when submitting messages
- Add whitespace-pre-wrap CSS to user message bubbles to render newlines
- Add className prop support to StreamingMarkdown component
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the user sends a message and the agent hasn't started streaming
yet, the chat area showed no visual feedback. Now a "Generating..."
spinner appears between message send and the first streaming content,
matching the existing indicator style used in StreamingMarkdown.
Closes MUL-224
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds a status bar and slide-out dashboard panel to the chat view that
shows subagent progress in real-time. Polls at 2s when active, 10s when
idle. Completed runs auto-hide after 5 minutes. Includes dismiss button
and 30s auto-dismiss for the status bar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove remarkMath and rehypeKatex plugins that caused text wrapping
issues by interpreting $ signs as LaTeX delimiters
- Configure remarkGfm with singleTilde: false to prevent single ~ from
being parsed as strikethrough (e.g., ~1000 should not become <del>)
- Only double tilde ~~text~~ now renders as strikethrough
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MessageSource type to track where user messages originate (local, gateway, channel)
- Broadcast inbound messages from all channels to local Desktop UI via Hub.onInboundMessage()
- Persist source field in JSONL session storage so it survives page refresh
- Display source icon (Monitor/Smartphone/Send) with tooltip for non-local user messages
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add CompactionItem component that renders a subtle inline notification
in the chat stream when the agent compacts its context window. Extends
Message type with "system" role and handles compaction_end events in
useChat's handleStream.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename channels.tsx to clients.tsx
- Remove standalone skills.tsx and tools.tsx pages
- Add agent/ directory for agent-related pages
- Update layout and navigation structure
- Add tabs component to ui package
- Update fonts and global styles
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add stop button to interrupt agent generation mid-stream. The send button
toggles to a stop icon during loading. Abort propagates from UI through
IPC to the Agent layer (PiAgentCore.abort()), preserving all partial
content in the agent's context so users can follow up immediately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add AppState module in core for managing app state persistence
- Add app-state IPC handlers for reading/writing onboarding state
- Hydrate onboarding state from file system on app startup
- Prevent flash by showing blank screen during hydration
- Update onboarding store to sync with file system
- Improve MulticaIcon with enhanced animation states
- Minor UI fixes in chat and device list components
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace @hugeicons/react with lucide-react across all packages
- Update all components to use Lucide icon components
- Add silent option to store refresh methods to control toast display
- Simplify icon usage with direct component imports
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Scroll cursor into view on content changes (e.g., Shift+Enter)
- Add scroll threshold and margin for better edge handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add remark-math + rehype-katex plugins to render inline ($...$) and
display ($$...$$) math expressions. Includes dark mode CSS overrides,
streaming block splitting for math fences, and math range exclusion
in link preprocessing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace ring-[3px] with ring-3 in button and input
- Use data-horizontal/data-vertical in separator
- Fix sidebar data attributes and RTL support
- Simplify tooltip provider nesting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>