558 Commits

Author SHA1 Message Date
Bohan Jiang
5a44c255fe docs: add v0.2.0 changelog entry (2026-04-15) (#1078) 2026-04-15 19:06:12 +08:00
Bohan Jiang
ce447c7f06 feat(agent): add custom CLI arguments support (#986)
* feat(agent): add custom CLI arguments support

Allow users to configure custom CLI arguments per agent that get
appended to the agent subprocess command at launch time. This enables
use cases like specifying different models (--model o3), max turns,
or other provider-specific flags without needing separate runtimes.

Changes:
- Add custom_args JSONB column to agent table (migration 041)
- Update API handler to accept/return custom_args in create/update
- Pass custom_args through claim endpoint to daemon
- Append custom_args to CLI commands for all agent backends
- Add ExecOptions.CustomArgs field in agent package
- Add Custom Args tab in agent detail UI
- Add --custom-args flag to CLI agent create/update commands

Closes MUL-802

* fix(agent): filter protocol-critical flags from custom_args

Add per-backend filtering of custom_args to prevent users from
accidentally overriding flags that the daemon hardcodes for its
communication protocol (e.g. --output-format, --input-format,
--permission-mode for Claude).

This follows the same pattern as custom_env's isBlockedEnvKey: we
only block the small, stable set of flags that would break the
daemon↔agent protocol — not every possible dangerous flag. Workspace
members are trusted for everything else.

Each backend defines its own blocked set:
- Claude: -p, --output-format, --input-format, --permission-mode
- Gemini: -p, --yolo, -o
- Codex: --listen
- OpenCode: --format
- OpenClaw: --local, --json, --session-id, --message
- Hermes: none (ACP is positional)

Includes unit tests for the filtering logic.

* fix(agent): address code review nits for custom_args

- Replace module-level `nextArgId` counter with `crypto.randomUUID()`
  in custom-args-tab.tsx to avoid SSR ID conflicts
- Add unit tests for custom args passthrough and blocked-arg filtering
  in both Claude and Gemini arg builders
2026-04-15 14:58:53 +08:00
Bohan Jiang
762e64d469 fix(agent): restrict custom_env visibility to owner/admin (#1046)
* fix(agent): restrict custom_env visibility to agent owner and workspace admin

Agent environment variables (custom_env) were visible to all workspace
members, exposing sensitive tokens. Now only the agent owner and
workspace owner/admin can view them — regular members receive the field
omitted (null) from API responses, and the frontend hides the
Environment tab accordingly.

Closes #1018

* fix(agent): show masked env keys to non-authorized users instead of hiding tab

Instead of completely hiding the Environment tab for non-owner/non-admin
users, show the variable keys with masked values (****) in a read-only
view. This lets members see which variables are configured without
exposing the actual values.

- Backend: mask values with "****" instead of nullifying custom_env
- Added custom_env_redacted boolean to API response
- Frontend: EnvTab supports readOnly mode with lock icon and muted styling
2026-04-15 13:06:49 +08:00
Naiyuan Qing
4b10c9354a fix(fonts): swap Geist Sans → Inter with explicit CJK fallback
Full-width Chinese punctuation (e.g. ,) was rendering at Latin-font
metrics, making it look half-width in the editor. Root cause: Geist is
Latin-only, and neither web (next/font) nor desktop (@fontsource) declared
any CJK fallback, so CJK chars inherited Geist's em-box width through
Chromium's per-character fallback.

- Web (apps/web/app/layout.tsx): Geist → Inter via next/font/google,
  with explicit fallback array: system fonts → PingFang SC (macOS) →
  Microsoft YaHei (Windows) → Noto Sans CJK SC (Linux) → sans-serif.
- Desktop: removed @fontsource/geist-sans, added @fontsource-variable/inter
  (single variable-weight file replaces 4 static weights). Updated
  --font-sans in globals.css to match web's fallback chain.
- Geist Mono kept for code blocks; mono chain has no CJK fallback by
  design (CJK is non-aligned in mono grids, listing CJK fonts would
  falsely signal alignment guarantees). Added Consolas to web mono for
  Windows symmetry with desktop.
- Cross-reference sync comments in both layout.tsx and globals.css:
  CJK tail must stay in sync; Inter primary differs by design (next/font
  injects `__Inter_xxx` with adjustFontFallback metric override;
  fontsource uses raw "Inter Variable").

Currently covers English + Simplified Chinese. When ja/ko i18n lands,
extend fallback tails with Hiragino Kaku Gothic ProN / Yu Gothic /
Apple SD Gothic Neo / Malgun Gothic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:45:14 +08:00
Jiayuan Zhang
d88fe2608e feat(autopilot): scheduled/triggered automations for AI agents (#1028)
* feat(autopilot): add scheduled/triggered automation for AI agents

Introduce the Autopilot feature — recurring automations that assign work
to AI agents on a schedule or manual trigger. Supports two execution
modes: create_issue (creates an issue for the agent to work on) and
run_only (directly enqueues an agent task without issue pollution).

Backend: migration (3 tables + 2 columns), sqlc queries, AutopilotService
with concurrency policies (skip/queue/replace), HTTP CRUD + trigger
endpoints, background cron scheduler (30s tick), event listeners for
issue→run and task→run status sync.

Frontend: types, API client methods, TanStack Query hooks with optimistic
mutations, realtime cache invalidation, list page with create dialog,
detail page with trigger management and run history, sidebar nav + routes
for both web and desktop apps.

* feat(autopilot): improve UX — trigger config, edit dialog, template gallery

- Replace raw cron input with friendly frequency tabs (Hourly/Daily/Weekdays/Weekly/Custom), time picker, and timezone dropdown defaulting to user's local timezone
- Fix Select components showing UUIDs instead of names (Base UI render function pattern)
- Add Edit button on detail page opening a unified edit dialog
- Remove project/concurrency/issue-title-template from create/edit (simplify for users)
- Add trigger configuration inline during autopilot creation
- Add template gallery on empty state (6 step-by-step workflow templates)
- Rename "Description" to "Prompt" throughout UI
- Inject autopilot run timestamp into issue description for agent date awareness
- Treat issue status "in_review" as run completion (fixes skip on next trigger)
- Make migration idempotent with IF NOT EXISTS clauses
2026-04-15 04:54:37 +08:00
Bohan Jiang
c79cfaf330 fix(auth): honor ?next= redirect through Google OAuth flow (#1024)
The login page now encodes the ?next= param into the Google OAuth state
so the auth callback can redirect to the right destination (e.g.
/invite/{id}) after login, instead of always going to /issues.
2026-04-15 00:52:12 +08:00
Bohan Jiang
60c5848794 feat(invitation): dedicated /invite/{id} page for accepting invitations (#1023)
The email CTA now deep-links to /invite/{id} instead of the generic app
URL. If the user isn't logged in, they're redirected to login with a
?next= param that brings them back to the invite page.

Changes:
- Backend: GET /api/invitations/{id} endpoint (enriched with workspace/inviter names)
- Backend: Email template now links to /invite/{invitationId}
- Frontend: Shared InvitePage component (packages/views/invite/)
- Frontend: Web route at (auth)/invite/[id], Desktop route at invite/:id
- Frontend: /invite/ excluded from navigation history persistence
2026-04-15 00:37:53 +08:00
Bohan Jiang
642c6ae5ee docs: add Gemini CLI to all documentation and landing page (#1022)
Gemini CLI support was added to the backend in v0.1.33 but was missing
from all user-facing documentation and the website. Added Gemini CLI
(and Hermes where missing) to the agents table, quickstart guides,
CLI reference, installation docs, self-hosting guide, and landing page
hero section with logo.
2026-04-15 00:28:02 +08:00
Bohan Jiang
c2a5ed73e8 fix(web): add /uploads/* rewrite for self-hosted deployments (#1010)
On self-hosted deployments where the frontend is the public entrypoint,
uploaded files return 404 because /uploads/* requests aren't proxied to
the backend. Add a rewrite rule following the existing pattern for /api/*,
/ws, and /auth/*.

Closes #1004
2026-04-14 21:34:47 +08:00
Jiang Bohan
609d2e06ae docs: remove desktop auto-update from v0.1.33 changelog 2026-04-14 16:35:59 +08:00
Jiang Bohan
7c436c0dcb docs: add v0.1.33 changelog entry (2026-04-14) 2026-04-14 16:33:41 +08:00
Bohan Jiang
0a998d1cef Merge pull request #846 from multica-ai/agent/j/feb218fd
feat(agent): support custom environment variables for router/proxy mode
2026-04-14 15:34:21 +08:00
KimSeongJun
8587243ab6 web: stabilize login and dashboard redirects (#900) 2026-04-14 02:26:24 +08:00
Jiang Bohan
a757f3a8c4 fix(selfhost): auto-derive WebSocket URL for LAN access (#896)
When NEXT_PUBLIC_WS_URL is not set, the WebSocket URL defaulted to
ws://localhost:8080/ws. This broke real-time features (chat streaming,
live updates, notifications) for self-hosted deployments accessed over
LAN — the browser tried connecting to localhost on the client machine
instead of the Docker host.

Now the web app derives the WebSocket URL from window.location, routing
through the existing Next.js /ws rewrite. This works for localhost, LAN,
and custom domain setups without any extra configuration.

Also adds NEXT_PUBLIC_WS_URL as a Docker build arg for explicit override,
and documents LAN access configuration in SELF_HOSTING_ADVANCED.md.

Closes #896
2026-04-14 01:42:42 +08:00
Jiayuan Zhang
576f20f2c7 refactor(cli): separate install from setup, redesign CLI configuration flow (#888)
Decouple install.sh from environment configuration — install.sh now only
installs the CLI binary (and optionally Docker via --with-server), while
all environment configuration moves to `multica setup` subcommands.

Key changes:
- install.sh: remove config writes, rename --local to --with-server
- multica setup: add cloud/self-host subcommands with --server-url,
  --app-url, --port, --frontend-port flags and --profile support
- Add config overwrite protection with interactive prompt
- Remove redundant commands: `config local`, `auth login` alias
- Replace silent multica.ai fallbacks with explicit errors
- Onboarding wizard: dynamically show correct setup command for
  Cloud vs Self-host environments
- Update all docs, landing page, and install scripts for consistency
2026-04-13 22:32:10 +08:00
Bohan Jiang
e2e5de1b26 docs: add v0.1.28 changelog entry (2026-04-13) (#867) 2026-04-13 19:13:53 +08:00
Jiayuan Zhang
01232fc2f9 feat(onboarding): add full-screen onboarding wizard for new workspaces (#852)
* feat(onboarding): add full-screen onboarding wizard for new workspaces

Replace auto-provisioned workspace with an interactive 4-step onboarding
wizard: Create Workspace → Connect Runtime → Create Agent → Get Started.

- Remove server-side ensureUserWorkspace() so new users land in onboarding
- Add onboarding wizard in packages/views/onboarding/ (4 steps)
- Wire login/OAuth callbacks to redirect to /onboarding when no workspace
- Add DashboardGuard onboardingPath fallback for workspace-less users
- Sidebar "Create workspace" navigates to /onboarding instead of modal
- Remove CreateWorkspaceModal (replaced by wizard step 1)
- Auto-generate workspace slug from name (no user-facing URL field)
- Unified CLI install flow: install.sh + multica setup (auto-detects local)
- Create onboarding issues on completion with interactive "Say hello" task

* test(auth): update workspace tests to match onboarding flow

Login no longer auto-creates workspaces — new users start with zero
workspaces and create one through the onboarding wizard. Update both
integration and handler tests to assert 0 workspaces after verify-code.
2026-04-13 17:59:51 +08:00
Jiang Bohan
4165401d16 feat(agent): support custom environment variables for router/proxy mode
Add per-agent custom_env configuration that gets injected into the agent
subprocess at launch time. This enables users to configure custom API
endpoints (ANTHROPIC_BASE_URL), API keys (ANTHROPIC_API_KEY), and cloud
provider modes (CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX) without
requiring code changes.

Changes:
- Migration 040: add custom_env JSONB column to agent table
- Backend: custom_env in agent CRUD API + claim endpoint
- Daemon: merge custom_env into subprocess environment variables
- Frontend: env var editor in agent settings (key-value pairs with
  visibility toggle for sensitive values)

Closes #816
Related: #807, #809
2026-04-13 16:47:56 +08:00
Bohan Jiang
418fe4b18e feat(desktop): implement Google login via deep link (#626)
Desktop Google login flow: click "Continue with Google" → opens default
browser to web login page with platform=desktop → Google OAuth completes
→ web callback redirects to multica://auth/callback?token=<jwt> →
Electron receives deep link, extracts token, completes login.

Changes:
- Register `multica://` protocol in Electron (main process + builder)
- Add single-instance lock with deep link forwarding (macOS + Win/Linux)
- Expose `desktopAPI.onAuthToken` and `openExternal` via preload IPC
- Add `loginWithToken(token)` to core auth store
- Pass `state=platform:desktop` through Google OAuth flow
- Web callback detects desktop state and redirects via deep link
- Desktop renderer listens for auth token and hydrates session
2026-04-13 15:33:14 +08:00
LinYushen
c8275605c9 fix(auth): fall back to token-mode WS for legacy localStorage users (#831)
* fix(auth): fall back to token-mode WS for users with legacy localStorage token

Users who logged in before the cookie-auth migration still have multica_token
in localStorage but no multica_auth cookie. Forcing cookieAuth=true for every
session caused their WebSocket upgrade to 401 with only workspace_id in the URL.

Detect the legacy token at boot and run that session in token mode (Bearer HTTP
+ URL-param WS). Pure cookie-mode is used only when no legacy token is present,
so new users get the intended path and legacy users migrate naturally on their
next logout/login cycle (logout already clears multica_token).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs(auth): note sunset plan for legacy-token WS fallback

Make the XSS-exposure tradeoff explicit and give future maintainers a
concrete signal (<1% of sessions) for when to delete the compat branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:40:03 +08:00
Naiyuan Qing
30725392ac Merge pull request #827 from multica-ai/refactor/workspace-list-to-react-query
refactor(workspace): migrate workspace list from Zustand to React Query
2026-04-13 14:29:10 +08:00
Naiyuan Qing
9581e4d870 test(web/login): wrap render with QueryClientProvider
LoginPage now calls useQueryClient() after the workspace list migration.
All test renders need a QueryClientProvider; add a createWrapper() helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 14:18:11 +08:00
Jiayuan Zhang
cb4f5071ab fix: update X link to @MulticaAI in readme and landing page (#826)
Replace outdated x.com/multica_hq with x.com/MulticaAI in:
- README.zh-CN.md
- Landing page shared config
- Landing page en/zh i18n files
2026-04-13 14:14:34 +08:00
Naiyuan Qing
c76ba2f58e fix(workspace): seed React Query cache at all list-acquisition points
- staleTime: 0 on fetchQuery after leave/delete so fresh data is fetched
- setQueryData before switchWorkspace in createWorkspace so sidebar is
  consistent on first render
- seed workspaceKeys.list() cache in login, Google callback, and
  settings save so the first useQuery(workspaceListOptions()) hit is free
- remove dead onError from WorkspaceStoreOptions (used only by the
  deleted refreshWorkspaces action)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 14:00:28 +08:00
Naiyuan Qing
43466a6402 refactor: migrate workspace list from Zustand to React Query
- Remove workspaces[] from workspace store — list is server state, belongs in React Query
- Change switchWorkspace(id) → switchWorkspace(ws) — caller provides full object from Query
- Remove createWorkspace/leaveWorkspace/deleteWorkspace store actions (duplicated mutations)
- Remove refreshWorkspaces store action — replaced by qc.fetchQuery + hydrateWorkspace
- Enhance useLeaveWorkspace/useDeleteWorkspace mutations to re-select workspace when current is removed
- useCreateWorkspace mutation now switches to new workspace on success
- AuthInitializer seeds React Query cache on boot to avoid double fetch
- Realtime sync: replace refreshWorkspaces() calls with qc.fetchQuery + hydrateWorkspace
- Sidebar reads workspace list from useQuery(workspaceListOptions()) instead of Zustand
- create-workspace modal and workspace settings tab use mutations directly
- AGENTS.md: rewrite to match current monorepo architecture, pointing to CLAUDE.md

Fixes workspace rename not updating sidebar without page refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 13:38:02 +08:00
LinYushen
95bfd7dd96 feat(auth): migrate auth token to HttpOnly Cookie & WebSocket Origin whitelist (#819)
* feat(auth): migrate auth token to HttpOnly cookie & implement WebSocket Origin whitelist

Security improvements from the MUL-566 audit report:

1. Auth token is now set as an HttpOnly, SameSite=Lax cookie on login,
   preventing XSS-based token theft. Cookie-based auth includes CSRF
   protection via double-submit cookie pattern. The Authorization header
   path is preserved for Electron desktop app and CLI/PAT clients.

2. WebSocket upgrader now validates the Origin header against a
   configurable allowlist (ALLOWED_ORIGINS env var), rejecting
   connections from unauthorized origins.

Backend: new auth cookie helpers, middleware reads cookie as fallback,
WS handler accepts cookie auth, Origin whitelist, logout endpoint.
Frontend: CSRF token in API headers, cookie-aware auth store and WS
client, web app opts into cookieAuth mode while desktop keeps tokens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(auth): address PR review — Strict cookies, HMAC-bound CSRF, origin sync

1. SameSite=Lax → SameSite=Strict per spec requirement
2. CSRF token now HMAC-signed with auth token (nonce.signature format),
   preventing subdomain cookie injection attacks
3. allowedWSOrigins uses atomic.Value to eliminate data race
4. Removed magic "cookie" sentinel string in WSProvider — pass null token
   and guard with boolean check instead
5. Removed dead delete uploadHeaders["Content-Type"] in API client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:13:35 +08:00
Jiayuan Zhang
04238bea22 chore: simplify v0.1.27 changelog — merge related items, remove trivial entries (#803) 2026-04-13 02:58:22 +08:00
Bohan Jiang
544b9bc971 docs: add v0.1.27 changelog entry (2026-04-12) (#790) 2026-04-12 23:35:48 +08:00
Jiayuan Zhang
5bae3368d7 feat(landing): add install command copy block to hero section (#743)
Adds a terminal-style one-click copy block below the CTA buttons showing
the curl install command, with a copy-to-clipboard button that shows a
checkmark on success.
2026-04-12 02:42:05 +08:00
Bohan Jiang
5def4b62e0 fix(web): upgrade Next.js to ^16.2.3 for CVE-2026-23869 (#706)
High-severity DoS vulnerability (CVSS 7.5) in App Router — specially
crafted requests to RSC endpoints cause excessive CPU consumption.
Patched in Next.js 16.2.3.

Ref: https://github.com/multica-ai/multica/issues/701
2026-04-11 18:23:13 +08:00
Jiang Bohan
1de88a9412 docs: add v0.1.23 and v0.1.24 changelog entries (2026-04-11) 2026-04-11 15:33:59 +08:00
Jiayuan Zhang
762bc92b2d fix(landing): replace "AI-Native Task Management" with landing page messaging (#670)
Use "Project Management for Human + Agent Teams" across all page titles,
OpenGraph metadata, and structured data to align with the actual landing
page hero and footer content.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:36:45 +08:00
Jiayuan Zhang
2d4b959407 fix(docker): remove COPY for non-existent tsconfig/node_modules (#661)
* fix(docker): remove COPY for non-existent tsconfig/node_modules

The @multica/tsconfig package has zero dependencies, so pnpm install
never creates a node_modules directory for it. The COPY --from=deps
instruction fails with "not found" during docker compose build.

Closes #658

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(docker): add dotenv as explicit dependency for web app

next.config.ts imports dotenv to load .env for REMOTE_API_URL, but
dotenv was never declared as a dependency. It worked locally as a
hoisted transitive dep but fails in Docker's stricter module resolution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: fix daemon setup instructions for local Docker deployments

The daemon setup section in SELF_HOSTING.md had production URLs as the
active example and local Docker URLs commented out. Since this is a
self-hosting guide, local Docker should be the primary example.

Key changes:
- Make local Docker URLs the default in daemon setup examples
- Add explicit warning that CLI defaults to hosted service
- Add 'multica config set' instructions for persistent setup
- Add link from Quick Start to daemon setup section
- Clarify that daemon runs on host machine, not inside Docker
- Update CLI_AND_DAEMON.md self-hosted section similarly

Closes #660

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 20:58:32 +08:00
Bohan Jiang
8056c49909 docs: add v0.1.22 changelog with categorized sections
* docs: add v0.1.22 changelog (2026-04-10)

* docs: rewrite v0.1.22 changelog with categorized sections

- Add features/improvements/fixes categories to changelog type and component
- Remove desktop/Electron mentions (not yet released)
- Rewrite all entries with detailed descriptions based on actual commit messages
- Component renders category headers when present, falls back to flat list for older entries
- Both en and zh updated

* docs: trim v0.1.22 changelog entries for conciseness
2026-04-10 16:54:28 +08:00
Jiayuan Zhang
ec71a41d8f feat(deploy): add full-stack Docker Compose for self-hosting
Add a one-command self-hosting setup: `docker compose -f docker-compose.selfhost.yml up -d`
starts PostgreSQL, backend (with auto-migration), and frontend.

Changes:
- docker-compose.selfhost.yml: full stack orchestration (postgres + backend + frontend)
- Dockerfile: add entrypoint.sh that auto-runs migrations before server start
- Dockerfile.web: multi-stage Next.js build with standalone output
- docker/entrypoint.sh: migration + server startup script
- .dockerignore: exclude unnecessary files from Docker builds
- apps/web/next.config.ts: conditional standalone output for Docker builds
- SELF_HOSTING.md: rewrite with Docker Compose as primary approach
- README.md: update self-host section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:11:18 +08:00
Naiyuan Qing
1dd8ca86c3 chore(web): remove unused Spinner, LoadingIndicator, and ThemeToggle
These components had zero consumers in the entire repo. Verified by
grep across both apps and all shared packages — they were dead code
left over from earlier iterations. The shadcn ui/spinner.tsx in
packages/ui is a separate component (Loader2-based) and is unaffected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 11:14:52 +08:00
Naiyuan Qing
aa6577c5b7 refactor(chat): extract chat data layer to packages/core/chat
Move chat queries, mutations, and store from apps/web/core/chat/ and
apps/web/features/chat/store.ts to packages/core/chat/. Refactor store
to use createChatStore({ storage }) factory pattern (mirrors auth store)
so it works in both web (localStorage) and desktop (Electron) without
direct browser API access. Register chat store in CoreProvider.initCore.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 11:14:36 +08:00
Naiyuan Qing
cc5e2e1712 test(views): rewrite shared component tests in packages/views
Move test ownership to where the code lives. LoginPage (28 tests),
IssuesPage (6 tests), IssueDetail (10 tests) now tested in
packages/views without framework-specific mocks. Old web tests
for shared components removed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:34:49 +08:00
Naiyuan Qing
b067eee487 chore: set up test infrastructure for shared packages
Add vitest configs to packages/core and packages/views. Test deps
added to pnpm catalog for unified versioning. Web test deps migrated
to catalog references. pnpm test now discovers all packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:34:03 +08:00
Naiyuan Qing
547b8839b2 refactor(auth): consolidate web login into shared LoginPage component
Extend shared LoginPage with CLI callback, workspace preference, and
token callback props. Web login page reduced from 393 lines to 52-line
thin wrapper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:45:17 +08:00
Naiyuan Qing
4c88a1318d chore(web): remove dead markdown component directory
The entire apps/web/components/markdown/ directory was unused —
all consumers already import from @multica/views/common/markdown.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:44:57 +08:00
Naiyuan Qing
05067f4960 refactor(search): extract search to packages/views for cross-platform reuse
Moved SearchCommand, SearchTrigger, and search store from apps/web/features/
to packages/views/search/. Replaced useRouter (next/navigation) with the
existing useNavigation() abstraction. Wired search into desktop layout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:27:36 +08:00
Naiyuan Qing
ba32f3a187 chore: add shared ESLint config + enforce strict tsconfig across packages
- 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>
2026-04-10 08:27:29 +08:00
Naiyuan Qing
a8c3137f3b Merge remote-tracking branch 'origin/main' into feat/desktop-app
# Conflicts:
#	apps/web/app/(dashboard)/layout.tsx
#	apps/web/app/globals.css
#	apps/web/app/layout.tsx
#	apps/web/core/chat/mutations.ts
#	apps/web/core/chat/queries.ts
#	apps/web/features/chat/components/chat-message-list.tsx
#	apps/web/features/chat/components/chat-window.tsx
#	apps/web/features/landing/components/landing-footer.tsx
#	packages/core/package.json
#	packages/views/layout/app-sidebar.tsx
2026-04-10 08:01:19 +08:00
Naiyuan Qing
79b4c75303 fix: pre-resolve merge conflicts with origin/main
Prepare for merge by integrating main's new features into the
extracted shared packages architecture:
- Chat feature (ChatFab, ChatWindow) added to web dashboard extra slot
- Sidebar redesign (3-group nav, search slot, user footer, runtime updates)
- WorkspaceIdProvider moved outside SidebarInset for extra components
- Social links, twitter metadata, showDevtools, latestCliVersion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 07:59:29 +08:00
Naiyuan Qing
042985d961 fix(desktop): resolve cross-platform boundary violations and deduplicate shared code
- 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>
2026-04-10 07:04:53 +08:00
Jiayuan Zhang
25080c6719 feat(chat): add session history panel to view archived conversations (#602)
Support viewing historical/archived chat sessions in the Master Agent chat
window. Previously, only active sessions were visible and archived ones were
permanently hidden.

Changes:
- Add ListAllChatSessionsByCreator SQL query (no status filter)
- Add ?status=all query param to GET /api/chat/sessions endpoint
- Add history button in chat header that opens a session list panel
- Sessions grouped by Active/Archived with archive action on active ones
- Clicking an archived session loads its messages in read-only mode
- Chat input disabled with "This session is archived" placeholder

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 02:40:55 +08:00
Jiayuan Zhang
7d5db1ce8b feat(sidebar): redesign layout for better space and grouping (#597)
* feat(sidebar): redesign sidebar layout for better space usage and grouping

- Split header into two rows: workspace switcher (full width) + search bar with new issue button
- Regroup navigation: Personal (Inbox, My Issues) + Workspace with label (Issues, Projects, Agents, Runtimes, Skills)
- Move Settings to SidebarFooter (like Linear)
- Search now renders as a full-width input-style button with ⌘K hint

Closes MUL-441

* fix(sidebar): style ⌘K shortcut as bordered badge matching project conventions

Use bordered kbd badge (bg-muted, border, font-mono) consistent with
search-command.tsx pattern. Render ⌘ symbol slightly larger for readability.

* feat(sidebar): add user profile info to footer

Show user avatar, name and email at the bottom of the sidebar
with a dropdown menu for logout, similar to the Lumis reference design.

* refactor(sidebar): move Settings back to Workspace nav, footer shows only user info

Settings is a navigable page that belongs with other nav items.
Footer now cleanly separates identity (user profile) from navigation.

* refactor(sidebar): split Workspace into Workspace + Configure groups

Split 6-item Workspace group into two cleaner groups:
- Workspace: Issues, Projects, Agents (core collaboration)
- Configure: Runtimes, Skills, Settings (infrastructure/admin)

* fix(sidebar): align search bar with nav items

Remove extra px-2 from search container and change button px-2.5 to px-2
so the search icon aligns at the same left offset as nav item icons.

* refactor(sidebar): make search and new issue regular menu items

Replace bordered input-style search bar and icon button with
SidebarMenuButton components so they share the same visual weight,
padding, and hover behavior as all other nav items.
2026-04-10 02:15:44 +08:00
Jiayuan Zhang
825e40358b feat(search): highlight matching keywords in search results (#598)
Add a HighlightText component that highlights the search query in both
issue titles and comment snippets using case-insensitive matching with
yellow highlight styling for light and dark modes.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 01:49:19 +08:00
Jiayuan Zhang
b5cccc8ac6 feat(landing): add OpenClaw and OpenCode to landing page (#596)
* feat(landing): add OpenClaw and OpenCode to landing page

The landing page hero "Works with" section and i18n text only listed
Claude Code and Codex. Updated to include all four supported runtimes:
Claude Code, Codex, OpenClaw, and OpenCode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(landing): remove X (Twitter) button from header nav

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 01:07:46 +08:00