* docs(i18n): translate documentation corpus to French (MUL-7637)
Add French (.fr.mdx) translations for all 45 docs pages plus meta.fr.json
navigation, mirroring the English source. Product and UI terms follow the
in-app French locale at packages/views/locales/fr/ (issue -> tâche,
run -> exécution, autopilot -> automatisation, Chat -> Discussion,
Settings -> Paramètres, etc.). Status and role identifiers stay lowercase
English per the conventions glossary, with the French UI label shown once
where they are defined.
Co-authored-by: multica-agent <[email protected]>
* feat(docs): serve French docs locale (MUL-7637)
Register fr in the docs i18n config and add the French Fumadocs chrome,
language-switcher label, and home hero copy. Fumadocs maps fr to Orama's
built-in French tokenizer, so search needs no custom localeMap entry.
Co-authored-by: multica-agent <[email protected]>
* feat(i18n): link French UI to French docs (MUL-7637)
Route French users from the landing page, runtime guides, the autopilot
webhook filter help, and the Slack/Lark/DingTalk/Telegram setup links to
/docs/fr. The four integration tabs and the runtime helper each carried a
copy of the same locale-prefix ternary; they now share docsLocalePrefix.
Co-authored-by: multica-agent <[email protected]>
* fix(i18n): localize remaining docs entry points (MUL-7637)
French users still reached English docs from the Help menu, the Agents and
Skills "Learn more" links, and the landing footer. The views links now use
docsLocalePrefix; the landing dictionaries take the docs href from
docsHrefForLocale, so locales that reuse another dictionary (French reuses
English) still link to their own docs.
Co-authored-by: multica-agent <[email protected]>
---------
Co-authored-by: multica-agent <[email protected]>
* feat(i18n): add French locale
Adds `fr` as a supported UI locale for web and desktop.
- 25 translated resource files under `packages/views/locales/fr/`, at full
parity with the English source (`locales/parity.test.ts` passes).
- Registers the locale in `SUPPORTED_LOCALES`, the views resource bundle, the
settings language picker, and the `HTML_LANG` maps for web and desktop.
- Translates the celestial workspace name list. Proper nouns with no
established French form are left unchanged.
- Landing page: adds the `FR` label but leaves the public `locales` array at
four, since the marketing copy is not translated.
- Onboarding templates map `fr` to English content, matching the existing
fallback for locales without authored templates.
- `pick-locale.test.ts` used `fr` as its example of an unsupported locale;
those assertions now use `es`, plus a new case asserting `fr-FR` resolves
to `fr`.
Terminology follows the glossary in
`apps/docs/content/docs/developers/conventions.mdx`. The UI uses the formal
register (vouvoiement) consistently.
* fix(i18n): translate the backlog status label in French
The French locale translated six of the seven issue statuses and left
`backlog` as "Backlog". The other locales translate all seven — `待规划`,
`백로그`, `バックログ` — so the odd one out was an oversight, not a choice.
`conventions.mdx` does say role and status enums stay in lowercase English,
but that rule is about surfacing the identifier inside prose ("switched to
`in_progress`"), not about the `status` display block, which every shipped
locale translates.
"À planifier" reads as a pair with "À faire" for `todo`, and matches what
`待规划` conveys: the issue exists but is not scheduled yet.
* fix(i18n): realign the French locale with main
Rebasing on main surfaced two drifts that the parity test caught:
- `settings.json` gained `shortcuts.fixed.open_settings` upstream; added
the French string.
- `search.json` lost its `pages.*` block in #7054, which now generates the
command palette's Pages group from the nav registry. Dropped the eight
French keys that no longer have an English counterpart.
* fix(i18n): resync the French locale with main
157 English keys had no French translation and 97 French keys no longer had an
English counterpart. The parity suite caught all of them.
Added: custom issue statuses (76 keys), the Telegram integration (55), issue
revision conflicts and the status catalogue (20), plugin panels and hook
activity (24), revoked agent access in chat (4), autopilot run quota and the
worktree execution mode (2).
Removed: 97 keys upstream has dropped or renamed, most of them under plugins.*.
Two shape changes worth naming, because a key count does not show them:
- plugins.install used to be the string "Install" and is now an object with
title/description/placeholder/review. A locale that keeps the old shape does
not have a missing key, it has a key of the wrong TYPE, and parity alone
stays silent about it — only writing to it fails.
- telegram_bind mirrors slack_bind key for key, so it is derived from the
existing translation with the service name substituted rather than written
again. Two texts that say the same thing drift when they are typed twice.
Register: vouvoiement throughout, consistent with the rest of the locale.
* fix(i18n): complete French locale integration and refresh translations
Co-authored-by: multica-agent <[email protected]>
---------
Co-authored-by: Lambda <[email protected]>
Co-authored-by: multica-agent <[email protected]>
Localize the web auth callback, 404 page, and root error boundary, plus the shared section-level ErrorBoundary.
Also fixes several pre-existing auth-path bugs surfaced during review:
- access_denied was unreachable (the !code branch preceded the error-param check)
- UserLocaleSync's reload could replay a consumed OAuth code and show 'Login Failed' after a successful sign-in
- Google token-exchange and userinfo provider failures were misreported as user-actionable causes
- checkSignupAllowed reported 'registration is disabled' for an allowlist miss
`app/[workspaceSlug]/layout.tsx` writes the platform workspace singleton from
render. The App Router can keep a previous workspace's layout mounted beside
the incoming one, and both re-render on their own query activity, so the
unguarded write let them alternate — every render flipping the singleton back
to its own slug, indefinitely.
Two things read that singleton and broke with it:
- `packages/core/realtime/provider.tsx` binds the realtime socket to the slug,
so each flip tore the socket down and rebuilt it against the other
workspace. Seen on a self-host as a `close 1005` / reconnect pair every
20-35s alternating workspace, with realtime updates lost for whichever
workspace the user was actually looking at.
- `packages/views/editor/extensions/mention-suggestion.tsx` reads it
synchronously when the user types `@`, then looks up the agent and member
caches by that id. Pointed at the other workspace those caches are cold, so
the mention list came back empty.
Gate the write on the live pathname. The URL is the source of truth for
workspace identity and `usePathname()` returns one value shared by every
mounted instance, so exactly one layout — the routed one — can define it, with
no ownership handshake. Desktop keeps its own protocol
(`workspace-route-layout.tsx`) because it has no URL bar to appeal to.
Co-authored-by: Claude Opus 5 <[email protected]>
MUL-6291. Vitest's own breakdown for `@multica/views` showed the shape of the
problem: environment 633s and import 644s against only 508s of actual test
execution. Two thirds of a cold frontend-test run went on building a jsdom per
file and importing its module graph, not on running assertions.
- 94 pure-logic `.test.ts` files across views/web/desktop now declare
`// @vitest-environment node`. Measured on the 45 converted views files:
environment 53.15s -> 4ms, wall 8.72s -> 2.03s. Candidates were picked by
module-graph analysis (skipping type-only imports) and rejected when the code
under test branches on `typeof window`/`document`, where node would silently
take the SSR path and still pass; the remainder were verified empirically and
reverted where they failed.
- The three jsdom setup files bail out when there is no DOM, so a node-env suite
can share them.
- schedule-editor: the pure state transitions (isFullDay, displayWindow,
timeAnchorOf, defaultAtTime, defaultEveryTime, clampWindow, toggleDay) move
out of the component into transitions.ts, with the full combination matrix as
a table-driven node-env suite. 34 cases in 3ms, replacing four DOM mounts.
- Cross-layer duplicates removed where a canonical layer already owns the
matrix: originSourceUrl (skills/lib/origin.test.ts) was re-run through the
refresh dialog and the detail page; needsSourceBackfill
(core/onboarding/needs-backfill.test.ts) through the backfill modal. Each
component keeps one wiring case naming the canonical file.
No behaviour change: the transitions extraction is a pure move, and every
removal names where the same contract is still covered.
Co-authored-by: Bohan-J <[email protected]>
Co-authored-by: multica-agent <[email protected]>
* i18n: add japanese locale
* fix: spacing issues
* refactor
* fix(desktop): set <html lang> before paint to avoid JA Kanji font flash
Switch the documentElement.lang sync from useEffect to useLayoutEffect so
lang is committed before the first paint. Otherwise Japanese desktop users
saw one frame of Kanji rendered with the Chinese-first fallback stack before
the html[lang|="ja"] CJK override applied. Also fix the stale selector in the
HTML_LANG comment (html[lang^="ja"] -> html[lang|="ja"]).
Addresses review nits on MUL-2893.
Co-authored-by: multica-agent <[email protected]>
* fix(docs): tokenize the ideographic iteration mark in JA search
Add U+3005 (々) to the Japanese search tokenizer character class. It sits just
below the kana blocks, so words like 様々 / 日々 / 個々 previously dropped the
mark and split awkwardly, hurting recall.
Addresses a review nit on MUL-2893.
Co-authored-by: multica-agent <[email protected]>
* fix(i18n): restore ja locale parity after merging main
Merging main brought new EN strings into agents/chat/onboarding/settings/
squads that the ja bundle (authored against an older snapshot) lacked, breaking
the locales parity test. Add the Japanese translations for the new keys
(workspace logo upload, agents runtime filter, chat session-history stop
dialog, onboarding social_github, squad archived status) and drop the two
renamed chat window keys (active_group / archived_group) that EN removed in
favour of history_group.
Fixes the failing @multica/views parity.test.ts on the FE CI for MUL-2893.
Co-authored-by: multica-agent <[email protected]>
---------
Co-authored-by: J <[email protected]>
Co-authored-by: multica-agent <[email protected]>
* feat(web): add use-cases content pipeline with welcome page (MUL-2349)
Wire fumadocs-mdx into apps/web with an independent collection rooted at
content/use-cases/. Add the first page at /use-cases/welcome (header + H1 +
prose + screenshot + footer) using the about-page visual shell.
- source.config.ts + lib/use-cases-source.ts (separate from apps/docs)
- features/landing/components/mdx/screenshot.tsx wraps next/image
- public/use-cases/welcome/screenshot-1.png placeholder (55KB)
- next.config.ts wraps NextConfig with createMDX()
- .gitignore + eslint ignore .source/
Co-authored-by: multica-agent <[email protected]>
* feat(web): bilingual db-boy use case with cookie locale (MUL-2349)
Extends the use-cases pipeline into the first real article.
- ZH + EN MDX (auto-data-analysis.{zh,en}.mdx) sharing three real
screenshots; sensitive fields on db-boy-profile.png (RDS host, DB
name, password) are blurred in-place.
- Cookie-based locale: /use-cases/<slug> reads multica-locale
server-side via lib/use-cases-i18n.ts (mirrors LandingLayout's
cookie + Accept-Language fallback). Same URL serves either language;
no [lang] segment so all other landing routes stay unchanged.
- Frontmatter schema (source.config.ts): z.looseObject with declared
hero_image / updated_at (required) / category (optional); a
preprocess converts YAML-auto-parsed Date back to a YYYY-MM-DD string.
- MDX components factory createMdxComponents(locale) routes the
secondary CTA to /docs/zh (ZH) or /docs (EN); internal MDX links
use <Link> for SPA nav; full-width and half-width colons both
trigger [CTA: ...] / [占位图: ...] markers; 副 and Secondary
both work as the secondary CTA prefix.
- Index page localizes hero / subtitle / card CTA / metadata; sort
fallback uses an epoch placeholder so undefined-order disappears.
- Landing header + footer surface use-cases entry in both locales.
- Detail route: sticky header, right-rail TOC with anchor jumps,
scroll-mt-[100px] on H2/H3 so anchor jumps don't slip under the
sticky header.
- Drop welcome demo page.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* fix(web): resolve code review blockers on use-cases PR
- Add `use-cases` to reserved_slugs.json + regenerate TS (P1: prevent
future workspace slug collision)
- Fix dead links in both MDX files: /features/* → /docs/* (P2)
- Remove duplicate brand suffix in page title metadata (nit)
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Co-authored-by: multica-agent <[email protected]>
* fix(web): align usecases locale routing
* chore: refresh web mdx lockfile
* fix(web): type mdx next config adapter
* fix(web): wrap settings route page
---------
Co-authored-by: multica-agent <[email protected]>
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
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) <[email protected]>
- 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 <[email protected]>
Add workspace list to sidebar dropdown with switching support, and a
create workspace dialog. Initialization now respects stored workspace ID.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Fix kanban board columns not adapting to available width (w-64 → flex-1)
- Fix workspace name not updating in sidebar after save in settings
- Fix comments leaking across issues when navigating between issue details
- Fix duplicate issue appearing on create (race between callback and WebSocket)
- Add real-time WebSocket listeners for agents and inbox pages
- Add `make check` one-click verification pipeline (typecheck + tests + E2E)
- Add E2E test fixtures for self-contained test data setup/teardown
- Add settings E2E test and updateWorkspace unit test
- Make `make start/setup` reuse existing PostgreSQL if already running
- Update CLAUDE.md with AI agent verification loop and E2E test patterns
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add missing Issue fields (parent_issue_id, acceptance_criteria, etc.) to test mocks
- Fix Agent mock fields to match actual type (runtime_config, owner_id, avatar_url)
- Import vi in test/helpers.tsx and add type annotation for mockAuthValue
- Add non-null assertions for array indexing in knowledge-base markdown renderer
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Replace all mock data with real API calls across pages (issues, agents, inbox, settings)
- Add AuthProvider context with JWT login/logout, member/agent name resolution
- Implement login page with email-based auth flow
- Add settings page with workspace editing and member list
- Wire up real-time WebSocket for live issue updates
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Remove Next.js rewrites proxy configuration
- Use NEXT_PUBLIC_API_URL for direct API requests
- Fixes ECONNRESET errors from proxy failures
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add common generateEncryptedId() utility in @multica/utils
- All Device IDs now use same encryption algorithm (40 hex chars)
- Web: store encrypted format directly in localStorage
- Desktop: use shared utility, accept encrypted ID from Web
- Hub: use shared utility for hub-id generation
- Telegram: use shared utility for device ID generation
- Gateway hook: use encrypted format for client connections
Algorithm: sha256(sha256(uuid).slice(0,32)).slice(0,8) + sha256(uuid).slice(0,32)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Web stores raw UUID, encrypts when transmitting (consistent with copilot-search)
- Desktop receives encrypted Device ID from Web login callback
- Desktop stores encrypted 40-char format in auth.json
- Update IPC types to include deviceId in auth callback
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add lib/auth.ts for cookie-based session storage
- Add AuthGuard component for route protection
- Update request.ts to include sid in Authorization header
- Update login-form.tsx to save session and redirect if authenticated
- Wrap ChatPage with AuthGuard
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add email/code login with verification
- Add Google OAuth login
- Add desktop callback API route
- Add request service with device ID handling
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace local UI component and utility imports with @multica/ui
subpath imports. Remove old components/ui/ directory, lib/utils.ts,
and globals.css. Configure postcss, next.config, and tsconfig for
monorepo UI package consumption.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add pnpm workspace and Turborepo configuration
- Extract Gateway SDK to packages/sdk as independent package
- Add Next.js + shadcn Web client in apps/web
- Update root package.json with turbo scripts
Co-Authored-By: Claude Opus 4.5 <[email protected]>